You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1889 lines
70 KiB
1889 lines
70 KiB
/****************************************************************************/
|
|
// nddapi.c
|
|
//
|
|
// RDP DD exported functions.
|
|
//
|
|
// Copyright (c) 1996-2000 Microsoft Corporation
|
|
/****************************************************************************/
|
|
|
|
#include <precmpdd.h>
|
|
#define hdrstop
|
|
|
|
#define TRC_FILE "nddapi"
|
|
#include <adcg.h>
|
|
#include <atrcapi.h>
|
|
|
|
#include <winddi.h>
|
|
|
|
#include <ndddata.c>
|
|
|
|
#include <nddapi.h>
|
|
#include <nshmapi.h>
|
|
#include <nsbcdisp.h>
|
|
#include <ncmdisp.h>
|
|
#include <nwdwioct.h>
|
|
#include <nschdisp.h>
|
|
#include <nbadisp.h>
|
|
#include <noadisp.h>
|
|
#include <nssidisp.h>
|
|
#include <noedisp.h>
|
|
#include <nchdisp.h>
|
|
|
|
#include <nddifn.h>
|
|
#include <nbainl.h>
|
|
|
|
|
|
#ifdef DC_DEBUG
|
|
/****************************************************************************/
|
|
/* Useful function for outputting lines to the debugger */
|
|
/****************************************************************************/
|
|
void DrvDebugPrint(char * str, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, str);
|
|
|
|
EngDebugPrint("RDPDD: ", str, ap);
|
|
}
|
|
|
|
void WDIcaBreakOnDebugger()
|
|
{
|
|
ULONG dummyBytesReturned;
|
|
ULONG status;
|
|
DC_BEGIN_FN("WDIcaBreakOnDebugger");
|
|
|
|
status = EngFileIoControl( ddWdHandle,
|
|
IOCTL_WDTS_DD_ICABREAKONDEBUGGER, 0, 0, 0, 0,
|
|
&dummyBytesReturned);
|
|
|
|
if (STATUS_SUCCESS != status) {
|
|
TRC_ERR((TB, "IOCTL_WDTS_DD_ICABREAKONDEBUGGER returned %lu",
|
|
status ));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
/* 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)
|
|
{
|
|
DC_BEGIN_FN("DrvEnableDriver");
|
|
|
|
#ifdef DC_DEBUG
|
|
// Initialize the trace level.
|
|
ddTrcType = TT_API1 | TT_API2 | TT_API3 | TT_API4;
|
|
DD_SET_STATE(DD_ENABLE_DRIVER);
|
|
#endif
|
|
|
|
#ifdef DDINT3
|
|
_asm int 3;
|
|
#endif
|
|
|
|
// 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)
|
|
return FALSE;
|
|
|
|
// Fill in as much as we can. Start with the entry points.
|
|
if (cj >= FIELDOFFSET(DRVENABLEDATA, pdrvfn) +
|
|
FIELDSIZE(DRVENABLEDATA, pdrvfn)) {
|
|
pded->pdrvfn = (DRVFN *)ddDriverFns;
|
|
TRC_DBG((TB, "Passing back driver functions %p", pded->pdrvfn));
|
|
}
|
|
|
|
// Size of our entry point array.
|
|
if (cj >= FIELDOFFSET(DRVENABLEDATA, c) + FIELDSIZE(DRVENABLEDATA, c)) {
|
|
pded->c = DD_NUM_DRIVER_INTERCEPTS;
|
|
TRC_DBG((TB, "Passing back function count %lu", 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 >= FIELDOFFSET(DRVENABLEDATA, iDriverVersion) +
|
|
FIELDSIZE(DRVENABLEDATA, iDriverVersion)) {
|
|
pded->iDriverVersion = DDI_DRIVER_VERSION_SP3;
|
|
TRC_DBG((TB, "Using driver type %lu", pded->iDriverVersion));
|
|
}
|
|
|
|
TRC_NRM((TB, "Num driver intercepts: %d", DD_NUM_DRIVER_INTERCEPTS));
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DrvDisableDriver - see NT DDK documentation.
|
|
/****************************************************************************/
|
|
VOID DrvDisableDriver(VOID)
|
|
{
|
|
DC_BEGIN_FN("DrvDisableDriver");
|
|
|
|
// Release any resources allocated in DrvEnableDriver.
|
|
TRC_NRM((TB, "DrvDisableDriver"));
|
|
|
|
DDTerm();
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* 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;
|
|
PDD_PDEV pPDev = NULL;
|
|
GDIINFO gdiInfoNew;
|
|
INT32 cModes;
|
|
PVIDEO_MODE_INFORMATION pVideoModeInformation = NULL;
|
|
INT32 cbModeSize;
|
|
|
|
DC_BEGIN_FN("DrvEnablePDEV");
|
|
|
|
// Make sure that we have large enough data to reference.
|
|
if (cjCaps >= sizeof(GDIINFO) && cjDevInfo >= sizeof(DEVINFO)) {
|
|
// Allocate a physical device structure; store the hDriver in it.
|
|
pPDev = EngAllocMem(0, sizeof(DD_PDEV), DD_ALLOC_TAG);
|
|
if (pPDev != NULL) {
|
|
// Don't zero the palette since we'll be setting that up soon.
|
|
memset(pPDev, 0, sizeof(DD_PDEV) - sizeof(pPDev->Palette));
|
|
pPDev->hDriver = hDriver;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "DrvEnablePDEV - Failed EngAllocMem"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Buffer size too small %lu %lu", cjCaps, cjDevInfo));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Set up the current screen mode information based upon the supplied
|
|
// mode settings.
|
|
DDInitializeModeFields(pPDev, (GDIINFO *)pdevcaps, &gdiInfoNew, pdi, pdm);
|
|
memcpy(pdevcaps, &gdiInfoNew, min(sizeof(GDIINFO), cjCaps));
|
|
|
|
// Since DrvGetModes is only called when the DD is test-loaded, we must
|
|
// get a mode count here so that we can determine if we're loaded into
|
|
// the console session.
|
|
cModes = DDGetModes(hDriver, &pVideoModeInformation, &cbModeSize);
|
|
if (cModes == -1) {
|
|
TRC_NRM((TB, "We are a chained console driver"));
|
|
ddConsole = TRUE;
|
|
// see DDK : must be set for a mirror driver
|
|
pdi->flGraphicsCaps |= GCAPS_LAYERED;
|
|
// to support alpha cursor
|
|
pdi->flGraphicsCaps2 |= GCAPS2_ALPHACURSOR;
|
|
} else {
|
|
if (cModes == 0) {
|
|
TRC_ERR((TB, "Failed to get the video modes."));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// Dump the returned GDIINFO details to the debugger.
|
|
TRC_ALT((TB, "Returned GDIINFO:"));
|
|
TRC_ALT((TB, " ulVersion %#x", gdiInfoNew.ulVersion));
|
|
TRC_ALT((TB, " ulTechnology %#x", gdiInfoNew.ulTechnology));
|
|
TRC_ALT((TB, " ulHorzSize %#x", gdiInfoNew.ulHorzSize));
|
|
TRC_ALT((TB, " ulVertSize %#x", gdiInfoNew.ulVertSize));
|
|
TRC_ALT((TB, " ulHorzRes %#x", gdiInfoNew.ulHorzRes));
|
|
TRC_ALT((TB, " ulVertRes %#x", gdiInfoNew.ulVertRes));
|
|
TRC_ALT((TB, " cBitsPixel %#x", gdiInfoNew.cBitsPixel));
|
|
TRC_ALT((TB, " cPlanes %#x", gdiInfoNew.cPlanes));
|
|
TRC_ALT((TB, " ulNumColors %#x", gdiInfoNew.ulNumColors));
|
|
TRC_ALT((TB, " flRaster %#x", gdiInfoNew.flRaster));
|
|
TRC_ALT((TB, " ulLogPixelsX %#x", gdiInfoNew.ulLogPixelsX));
|
|
TRC_ALT((TB, " ulLogPixelsY %#x", gdiInfoNew.ulLogPixelsY));
|
|
TRC_ALT((TB, " flTextCaps %#x", gdiInfoNew.flTextCaps));
|
|
TRC_ALT((TB, " ulDACRed %#x", gdiInfoNew.ulDACRed));
|
|
TRC_ALT((TB, " ulDACGreen %#x", gdiInfoNew.ulDACGreen));
|
|
TRC_ALT((TB, " ulDACBlue %#x", gdiInfoNew.ulDACBlue));
|
|
TRC_ALT((TB, " ulAspectX %#x", gdiInfoNew.ulAspectX));
|
|
TRC_ALT((TB, " ulAspectY %#x", gdiInfoNew.ulAspectY));
|
|
TRC_ALT((TB, " ulAspectXY %#x", gdiInfoNew.ulAspectXY));
|
|
TRC_ALT((TB, " xStyleStep %#x", gdiInfoNew.xStyleStep));
|
|
TRC_ALT((TB, " yStyleStep %#x", gdiInfoNew.yStyleStep));
|
|
TRC_ALT((TB, " denStyleStep %#x", gdiInfoNew.denStyleStep));
|
|
TRC_ALT((TB, " ptlPhysOffset.x %#x", gdiInfoNew.ptlPhysOffset.x));
|
|
TRC_ALT((TB, " ptlPhysOffset.y %#x", gdiInfoNew.ptlPhysOffset.y));
|
|
TRC_ALT((TB, " szlPhysSize.cx %#x", gdiInfoNew.szlPhysSize.cx));
|
|
TRC_ALT((TB, " szlPhysSize.cy %#x", gdiInfoNew.szlPhysSize.cy));
|
|
TRC_ALT((TB, " ulNumPalReg %#x", gdiInfoNew.ulNumPalReg));
|
|
TRC_ALT((TB, " ulVRefresh %#x", gdiInfoNew.ulVRefresh));
|
|
TRC_ALT((TB, " ulBltAlignment %#x", gdiInfoNew.ulBltAlignment));
|
|
TRC_ALT((TB, " ulPanningHorzRes %#x", gdiInfoNew.ulPanningHorzRes));
|
|
TRC_ALT((TB, " ulPanningVertRes %#x", gdiInfoNew.ulPanningVertRes));
|
|
#endif
|
|
|
|
// Set the default palette.
|
|
if (DDInitializePalette(pPDev, pdi)) {
|
|
// We have successfully initialized - return the new PDEV.
|
|
rc = (DHPDEV)pPDev;
|
|
TRC_NRM((TB, "PDEV 0x%p screen format %lu", pPDev,
|
|
pPDev->iBitmapFormat));
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Failed to initialize palette"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
// This is a temporary buffer. We use it to call DDGetModes in order
|
|
// to find out if we are in chained mode or not. We always free it.
|
|
if (pVideoModeInformation != NULL) {
|
|
EngFreeMem(pVideoModeInformation);
|
|
pVideoModeInformation = NULL;
|
|
}
|
|
|
|
// Release any resources if we failed to initialize.
|
|
if (rc != NULL) {
|
|
DD_UPD_STATE(DD_ENABLE_PDEV);
|
|
}
|
|
else {
|
|
// In case pPDev is allocated this will free first try to free the
|
|
// palette (if any) and then it will free pPDev.
|
|
DrvDisablePDEV((DHPDEV)pPDev);
|
|
DD_UPD_STATE(DD_ENABLE_PDEV_ERR);
|
|
}
|
|
|
|
TRC_DBG((TB, "Returning %p", rc));
|
|
|
|
DC_END_FN();
|
|
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)
|
|
{
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
|
|
DC_BEGIN_FN("DrvDisablePDEV");
|
|
|
|
TRC_NRM((TB, "Disabling PDEV %p", dhpdev));
|
|
|
|
// Free the resources we allocated for the display.
|
|
if (pPDev != NULL) {
|
|
// Destroy the default palette, if created.
|
|
if (pPDev->hpalDefault != 0) {
|
|
EngDeletePalette(pPDev->hpalDefault);
|
|
pPDev->hpalDefault = 0;
|
|
}
|
|
|
|
EngFreeMem(pPDev);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvCompletePDEV - see NT DDK documentation */
|
|
/* */
|
|
/* Stores the HPDEV, the engine's handle for this PDEV, in the DHPDEV. */
|
|
/****************************************************************************/
|
|
VOID DrvCompletePDEV(DHPDEV dhpdev, HDEV hdev)
|
|
{
|
|
DC_BEGIN_FN("DrvCompletePDEV");
|
|
|
|
// Store the device handle for our display handle.
|
|
TRC_NRM((TB, "Completing PDEV %p", dhpdev));
|
|
|
|
((PDD_PDEV)dhpdev)->hdevEng = hdev;
|
|
DD_UPD_STATE(DD_COMPLETE_PDEV);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvShadowConnect - called when the display driver should start */
|
|
/* shadowing. */
|
|
/* */
|
|
/* Primary job seems to be getting the shadow target WD up and running by */
|
|
/* pretending the display driver is coming up for the first time. Also */
|
|
/* */
|
|
/* Params: IN - pClientThinwireData (DD data from client) */
|
|
/* IN - ThinwireDataLength (length of data) */
|
|
/****************************************************************************/
|
|
BOOL DrvShadowConnect(PVOID pClientThinwireData, ULONG ThinwireDataLength)
|
|
{
|
|
TSHARE_DD_SHADOWSYNC_IN shadowSync;
|
|
ULONG bytesReturned;
|
|
NTSTATUS status;
|
|
BOOL rc = FALSE;
|
|
|
|
DC_BEGIN_FN("DrvShadowConnect");
|
|
|
|
DD_UPD_STATE(DD_SHADOW_SETUP);
|
|
|
|
// Make sure we are still connected! TODO: Restrict to only one shadow for
|
|
// now...
|
|
TRC_ERR((TB, "Shadow Connect: %p [%ld]",
|
|
pClientThinwireData,
|
|
ThinwireDataLength));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_SHADOWCONNECT,
|
|
pClientThinwireData, ThinwireDataLength, ddConnected, pddTSWdShadow);
|
|
#endif
|
|
|
|
if ((ddConnected) && (pddTSWdShadow == NULL)) {
|
|
// Drive the DD and WD into a disconnected state. Indicate this is in
|
|
// preparation for a shadow session to disable saving the persistent key
|
|
// database, etc. It also has the effect of destroying the SHM and
|
|
// taking down all of the related cache information and encoding state.
|
|
ddIgnoreShadowDisconnect = FALSE;
|
|
TRC_ERR((TB, "Disconnecting stack prior to shadow"));
|
|
DDDisconnect(TRUE);
|
|
TRC_ERR((TB, "Done disconnecting"));
|
|
|
|
// Reconnect to the WD to establish the shadow session
|
|
TRC_ERR((TB, "Reinitializing primary/shadow stacks: ddConnected(%ld)",
|
|
ddConnected));
|
|
|
|
// If both stacks connected successfully, reestablish the SHM and
|
|
// recreate the caches and encoding state.
|
|
if (DDInit(NULL, TRUE, FALSE, (PTSHARE_VIRTUAL_MODULE_DATA) pClientThinwireData,
|
|
ThinwireDataLength)) {
|
|
#ifdef DC_HICOLOR
|
|
// Get the shadower caps - in particular, it may have changed its
|
|
// cache caps because of a color depth change
|
|
PTSHARE_VIRTUAL_MODULE_DATA pShadowCaps;
|
|
ULONG dataLen = 256;
|
|
|
|
// Supply a small amount of memory so the Wd can tell us how much
|
|
// it actually needs - we can't just use the returned length from
|
|
// EngFileIoControl since when the IOCTL gets passed to both the
|
|
// primary and shadow stacks, the shadow's result overwrites the
|
|
// primary's result. Doh!
|
|
pShadowCaps = EngAllocMem(FL_ZERO_MEMORY,
|
|
dataLen,
|
|
DD_ALLOC_TAG);
|
|
|
|
if (pShadowCaps)
|
|
{
|
|
// First pass tells us the size we need for the caps
|
|
TRC_ERR((TB, "Getting shadow caps len..."));
|
|
status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_QUERY_SHADOW_CAPS,
|
|
NULL, 0,
|
|
pShadowCaps, dataLen,
|
|
&dataLen);
|
|
|
|
if (pShadowCaps->capsLength)
|
|
{
|
|
TRC_ERR((TB, "Getting shadow caps..."));
|
|
// remember this is the *caps* len - we need a bit
|
|
// extra for the rest of a vurtual module data structure
|
|
dataLen = pShadowCaps->capsLength + sizeof(unsigned);
|
|
// Free the old memory!
|
|
EngFreeMem(pShadowCaps);
|
|
pShadowCaps = EngAllocMem(FL_ZERO_MEMORY,
|
|
dataLen,
|
|
DD_ALLOC_TAG);
|
|
if (pShadowCaps)
|
|
{
|
|
// now we'll get the data
|
|
status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_QUERY_SHADOW_CAPS,
|
|
NULL, 0,
|
|
pShadowCaps, dataLen,
|
|
&dataLen);
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, "Couldn't get memory for shadow caps"));
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, "Unexpected status %08lx", status));
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, "Couldn't get memory for shadow caps"));
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
TRC_ERR((TB, "Couldn't get updated shadow caps"));
|
|
DC_QUIT;
|
|
}
|
|
#endif
|
|
|
|
// Tell the shadow target and shadow client(s) to synchronize
|
|
TRC_ERR((TB, "Shadow Connect - WD Sync Start"));
|
|
shadowSync.pShm = pddShm;
|
|
#ifdef DC_HICOLOR
|
|
shadowSync.capsLen = pShadowCaps->capsLength;
|
|
shadowSync.pShadowCaps = &pShadowCaps->combinedCapabilities;
|
|
#endif
|
|
|
|
status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_SHADOW_SYNCHRONIZE, &shadowSync,
|
|
sizeof(shadowSync), NULL, 0, &bytesReturned);
|
|
TRC_ERR((TB, "Shadow Connect - WD Sync End"));
|
|
|
|
#ifdef DC_HICOLOR
|
|
// release the caps memory
|
|
if (pShadowCaps)
|
|
{
|
|
EngFreeMem(pShadowCaps);
|
|
}
|
|
#endif
|
|
|
|
|
|
// Free all pending orders. This is OK as we will get a full redraw
|
|
// when the shadow starts
|
|
BAResetBounds();
|
|
|
|
// With Direct Encoding, at this point the orders in the order
|
|
// heap have already changed the encoding state, blowing away
|
|
// orders at this point will cause inconsistent state of the encoding
|
|
// table between the server and client. This is because we keep
|
|
// the last order type sent, so blowing away orders here means
|
|
// order type will not be sent to the client, but the server encoding
|
|
// table and state still kept the last order state. It's almost
|
|
// impossible to rewind the orders at this point. So, we simply have
|
|
// to send the orders to the client to keep order encoding state
|
|
// consistent.
|
|
//OA_DDSyncUpdatesNow();
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB,"Could not synchronize primary/shadow stacks: %lx",
|
|
status));
|
|
}
|
|
|
|
rc = NT_SUCCESS(status);
|
|
}
|
|
|
|
else {
|
|
TRC_ERR((TB,"Could not connect to primary/shadow stacks"));
|
|
}
|
|
}
|
|
|
|
// TODO: This is a temporary restriction until we allow n-way shadowing.
|
|
// Rejecting this connection causes us to get an associated
|
|
// DrvShadowDisconnect() which we need to ignore. See bug 229479
|
|
else {
|
|
TRC_ERR((TB, "Shadow Connect: already shadowing -> reject!"));
|
|
ddIgnoreShadowDisconnect = TRUE;
|
|
rc = STATUS_CTX_SHADOW_DENIED;
|
|
}
|
|
|
|
#ifdef DC_HICOLOR
|
|
DC_EXIT_POINT:
|
|
#endif
|
|
DD_CLR_STATE(DD_SHADOW_SETUP);
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvShadowDisconnect - called when the display driver should stop */
|
|
/* shadowing. */
|
|
/* */
|
|
/* Primary job seems to be telling the shadow target WD that shadowing is */
|
|
/* stopping and potentially restoring the former capability set for the */
|
|
/* target. */
|
|
/* */
|
|
/* Params: IN - pClientThinwireData (DD data from client) */
|
|
/* IN - ThinwireDataLength (length of data) */
|
|
/****************************************************************************/
|
|
BOOL DrvShadowDisconnect(PVOID pThinwireData, ULONG ThinwireDataLength)
|
|
{
|
|
|
|
NTSTATUS status;
|
|
ULONG bytesReturned;
|
|
TSHARE_DD_DISCONNECT_IN disconnIn;
|
|
|
|
DC_BEGIN_FN("DrvShadowDisconnect");
|
|
|
|
// Now tell the WD we're disconnecting. We don't do anything with a
|
|
// failure here - there's no point - we're already disconnecting!
|
|
TRC_ERR((TB, "Shadow Disconnect: %p [%ld]", pThinwireData,
|
|
ThinwireDataLength));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_SHADOWDISCONNECT,
|
|
pThinwireData, ThinwireDataLength, ddConnected, ddIgnoreShadowDisconnect);
|
|
#endif
|
|
|
|
if (ddConnected) {
|
|
// For now we are limited to one shadow per session. Any subsequent
|
|
// attempts will be rejected, but we must ignore the associated
|
|
// and unnecessary disconnect!
|
|
if (!ddIgnoreShadowDisconnect) {
|
|
|
|
pddShm->pShadowInfo = NULL;
|
|
disconnIn.pShm = pddShm;
|
|
disconnIn.bShadowDisconnect = FALSE;
|
|
|
|
status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_SHADOW_DISCONNECT, &disconnIn,
|
|
sizeof(disconnIn), NULL, 0, &bytesReturned);
|
|
TRC_ERR((TB, "Status on Shadow Disc IOCtl to WD %lu", status));
|
|
pddTSWdShadow = NULL;
|
|
|
|
// Update capabilities now that a party left the share
|
|
TRC_ERR((TB, "Updating new capabilities"));
|
|
|
|
// Initiate a disconnect for shadow exiting
|
|
DDDisconnect(TRUE);
|
|
TRC_ERR((TB, "Done disconnecting"));
|
|
|
|
// Reconnect to the WD to establish the primary session
|
|
TRC_ERR((TB, "Reinitializing primary stack: ddConnected(%ld)",
|
|
ddConnected));
|
|
|
|
// If primary stack connected successfully, reestablish the SHM and
|
|
// recreate the caches and encoding state.
|
|
if (DDInit(NULL, TRUE, FALSE, NULL, 0)) {
|
|
TRC_NRM((TB, "Reintialized the DD"));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Failed to initialize DD Components"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
else {
|
|
ddIgnoreShadowDisconnect = FALSE;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// else we have already been disconnected so just return an error
|
|
else {
|
|
status = STATUS_FILE_CLOSED;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return NT_SUCCESS(status);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* 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)
|
|
{
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
SIZEL sizl, tempSizl;
|
|
HSURF rc = 0;
|
|
ULONG memSize;
|
|
PBYTE newFrameBuf;
|
|
|
|
HANDLE SectionObject = NULL;
|
|
|
|
DC_BEGIN_FN("DrvEnableSurface");
|
|
|
|
TRC_NRM((TB, "Enabling surface for %p", dhpdev));
|
|
DD_UPD_STATE(DD_ENABLE_SURFACE_IN);
|
|
|
|
// Have GDI create the actual SURFOBJ.
|
|
sizl.cx = pPDev->cxScreen;
|
|
sizl.cy = pPDev->cyScreen;
|
|
|
|
/************************************************************************/
|
|
/* An RDP display driver has a bitmap where GDI does all its drawing, */
|
|
/* since it is the only driver in the IWS. We need to allocate the */
|
|
/* bitmap ourselves in order to know its address. */
|
|
/* */
|
|
/* We allocate a Frame Buffer at DrvEnableSurface time to make */
|
|
/* sure that the frame buffer surface is same as the device surface */
|
|
/* GDI thinks. This will prevent a lot of mismatch reconnect condition */
|
|
/************************************************************************/
|
|
#ifdef DC_HICOLOR
|
|
if ((pPDev->cClientBitsPerPel != ddFrameBufBpp + 1) ||
|
|
(pddFrameBuf == NULL) ||
|
|
(ddFrameBufX < sizl.cx) || (ddFrameBufY < sizl.cy))
|
|
#else
|
|
if ((pPDev->cClientBitsPerPel != ddFrameBufBpp) ||
|
|
(ddFrameBufX != sizl.cx) || (ddFrameBufY != sizl.cy))
|
|
#endif
|
|
{
|
|
// Allocate a new one. Note that we do not free the old one here -
|
|
// that's done in DrvDisableSurface.
|
|
memSize = TS_BYTES_IN_BITMAP(pPDev->cxScreen,
|
|
pPDev->cyScreen,
|
|
pPDev->cClientBitsPerPel);
|
|
|
|
newFrameBuf = (PBYTE)EngAllocSectionMem(&SectionObject,
|
|
FL_ZERO_MEMORY,
|
|
memSize,
|
|
DD_ALLOC_TAG);
|
|
|
|
if (newFrameBuf == NULL) {
|
|
TRC_ERR((TB, "DrvEnableSurface - "
|
|
"Failed FrameBuf EngAllocSectionMem for %lu bytes", memSize));
|
|
newFrameBuf = (PBYTE)EngAllocMem(FL_ZERO_MEMORY,
|
|
memSize,
|
|
DD_ALLOC_TAG);
|
|
SectionObject = NULL;
|
|
}
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - Instance count section memory objects
|
|
else {
|
|
dbg_ddSectionAllocs++;
|
|
TRC_DBG(( TB, "DrvEnableSurface - %d outstanding surfaces allocated",
|
|
dbg_ddSectionAllocs ));
|
|
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_ALLOC_SECTIONOBJ,
|
|
dbg_ddSectionAllocs, 0, newFrameBuf, SectionObject);
|
|
}
|
|
#endif
|
|
|
|
TRC_NRM((TB, "Reallocate Frame Buffer %p, SectionObject %p", newFrameBuf, SectionObject));
|
|
|
|
if (newFrameBuf == NULL) {
|
|
TRC_ERR((TB, "DrvEnableSurface - "
|
|
"Failed FrameBuf EngAllocMem for %lu bytes", memSize));
|
|
if (pddFrameBuf == NULL) {
|
|
// Reset the frame buffer size back to 0.
|
|
ddFrameBufX = ddFrameBufY = 0;
|
|
}
|
|
DC_QUIT;
|
|
}
|
|
|
|
pddFrameBuf = newFrameBuf;
|
|
ddFrameBufX = sizl.cx;
|
|
ddFrameBufY = sizl.cy;
|
|
ddFrameBufBpp = pPDev->cClientBitsPerPel;
|
|
ddFrameIFormat = pPDev->iBitmapFormat;
|
|
|
|
ddSectionObject = SectionObject;
|
|
}
|
|
|
|
// Create the frame buffer surface.
|
|
tempSizl.cx = ddFrameBufX;
|
|
tempSizl.cy = ddFrameBufY;
|
|
|
|
pPDev->hsurfFrameBuf = (HSURF)EngCreateBitmap(tempSizl,
|
|
TS_BYTES_IN_SCANLINE(ddFrameBufX, ddFrameBufBpp),
|
|
ddFrameIFormat, BMF_TOPDOWN, (PVOID)pddFrameBuf);
|
|
|
|
|
|
if (pPDev->hsurfFrameBuf == 0) {
|
|
TRC_ERR((TB, "Could not allocate surface"));
|
|
DC_QUIT;
|
|
|
|
}
|
|
|
|
// Update Frame Buffer pointers in PDEV.
|
|
pPDev->pFrameBuf = pddFrameBuf;
|
|
pPDev->SectionObject = ddSectionObject;
|
|
|
|
// Associate the frame buffer with the pdev.
|
|
if (EngAssociateSurface(pPDev->hsurfFrameBuf, pPDev->hdevEng, 0)) {
|
|
// Get a pointer to the frame buffer SURFOBJ.
|
|
pPDev->psoFrameBuf = EngLockSurface(pPDev->hsurfFrameBuf);
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "EngAssociateSurface failed: hsurfFrameBuf(%p)",
|
|
pPDev->hsurfFrameBuf));
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create a device surface. This is what we will pass back to the */
|
|
/* Graphics Engine. The fact that it is a device surface forces all */
|
|
/* drawing to come through the display driver. */
|
|
/* */
|
|
/* We pass the Frame Buffer SURFOBJ pointer as the DHSURF, so we can */
|
|
/* easily convert the (SURFOBJ *) parameters in the Drv... functions */
|
|
/* into real Frame Buffer SURFOBJ pointers: */
|
|
/* */
|
|
/* psoFrameBuf = (SURFOBJ *)(psoTrg->dhsurf); */
|
|
/************************************************************************/
|
|
pPDev->hsurfDevice = EngCreateDeviceSurface((DHSURF)pPDev->psoFrameBuf,
|
|
sizl, pPDev->iBitmapFormat);
|
|
|
|
// Now associate the device surface and the PDEV.
|
|
if (!EngAssociateSurface(pPDev->hsurfDevice, pPDev->hdevEng,
|
|
pPDev->flHooks)) {
|
|
TRC_ERR((TB, "DrvEnableSurface - Failed EngAssociateSurface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_NRM((TB, "hsurfFrameBuf(%p) hsurfDevice(%p) psoFrameBuf(%p)",
|
|
pPDev->hsurfFrameBuf, pPDev->hsurfDevice, pPDev->psoFrameBuf));
|
|
|
|
// Finally initialize the DD components, if necessary.
|
|
if (ddInitPending) {
|
|
TRC_NRM((TB, "DD init pending"));
|
|
ddInitPending = FALSE;
|
|
if (!DDInit(pPDev, FALSE, FALSE, NULL, 0)) {
|
|
TRC_ERR((TB, "Failed to initialize DD Components"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else {
|
|
// Don't do this is we're not connected.
|
|
if (ddConnected && pddShm != NULL) {
|
|
TRC_ALT((TB, "Re-enable surface"));
|
|
|
|
// Initialization not pending - this must be a desktop change.
|
|
// Flush the SDA & Order Heap.
|
|
TRC_ALT((TB, "New surface"));
|
|
|
|
BAResetBounds();
|
|
|
|
// With Direct Encoding, at this point the orders in the order
|
|
// heap have already changed the encoding state, blowing away
|
|
// orders at this point will cause inconsistent state of the encoding
|
|
// table between the server and client. This is because we keep
|
|
// the last order type sent, so blowing away orders here means
|
|
// order type will not be sent to the client, but the server encoding
|
|
// table and state still kept the last order state. It's almost
|
|
// impossible to rewind the orders at this point. So, we simply have
|
|
// to send the orders to the client to keep order encoding state
|
|
// consistent.
|
|
//OA_DDSyncUpdatesNow();
|
|
|
|
// SBC_DDSync(); // TODO: Determine how this affects shadowing!!!
|
|
|
|
DD_UPD_STATE(DD_REINIT);
|
|
}
|
|
else {
|
|
TRC_ALT((TB, "Not connected"));
|
|
}
|
|
}
|
|
|
|
// We have successfully associated the surface so return it to the GDI.
|
|
rc = pPDev->hsurfDevice;
|
|
DD_UPD_STATE(DD_ENABLE_SURFACE_OUT);
|
|
TRC_NRM((TB, "Enabled surface for %p, FB %p", pPDev, pPDev->pFrameBuf));
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
// Tidy up any resources if we failed.
|
|
if (rc == 0) {
|
|
DrvDisableSurface((DHPDEV) pPDev);
|
|
DD_UPD_STATE(DD_ENABLE_SURFACE_ERR);
|
|
}
|
|
|
|
DC_END_FN();
|
|
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)
|
|
{
|
|
BOOL rc;
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
|
|
DC_BEGIN_FN("DrvDisableSurface");
|
|
|
|
TRC_NRM((TB, "Disabling surface for %p", dhpdev));
|
|
|
|
if (pPDev->psoFrameBuf != NULL) {
|
|
EngUnlockSurface(pPDev->psoFrameBuf);
|
|
pPDev->psoFrameBuf = NULL;
|
|
}
|
|
|
|
if (pPDev->hsurfDevice != 0) {
|
|
TRC_DBG((TB, "Deleting device surface"));
|
|
EngDeleteSurface(pPDev->hsurfDevice);
|
|
pPDev->hsurfDevice = 0;
|
|
}
|
|
|
|
// Delete the Frame Buffer only if it is not still in use.
|
|
if (pPDev->hsurfFrameBuf != 0) {
|
|
TRC_DBG((TB, "Deleting frame buffer surface"));
|
|
EngDeleteSurface(pPDev->hsurfFrameBuf);
|
|
pPDev->hsurfFrameBuf = 0;
|
|
}
|
|
|
|
if ((pPDev->pFrameBuf != NULL) && (pPDev->pFrameBuf != pddFrameBuf)) {
|
|
if (pPDev->SectionObject != NULL) {
|
|
TRC_NRM((TB, "Freeing section frame buffer %p", pPDev->pFrameBuf));
|
|
rc = EngFreeSectionMem(pPDev->SectionObject, (PVOID)pPDev->pFrameBuf);
|
|
if (!rc) {
|
|
TRC_ABORT((TB, "EngFreeSectionMem failed, section object will "
|
|
"leak"));
|
|
#ifdef DC_DEBUG
|
|
WDIcaBreakOnDebugger();
|
|
#endif // DC_DEBUG
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
else {
|
|
// NT BUG 539912 - Instance count section memory objects
|
|
dbg_ddSectionAllocs--;
|
|
TRC_DBG(( TB, "DrvDisableSurface - %d outstanding surfaces allocated",
|
|
dbg_ddSectionAllocs ));
|
|
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FREE_SECTIONOBJ_SURFACE,
|
|
dbg_ddSectionAllocs, 0, pddFrameBuf, ddSectionObject);
|
|
}
|
|
#endif
|
|
pPDev->SectionObject = NULL;
|
|
} else {
|
|
TRC_NRM((TB, "Freeing frame buffer %p", pPDev->pFrameBuf));
|
|
EngFreeMem((PVOID)pPDev->pFrameBuf);
|
|
}
|
|
pPDev->pFrameBuf = NULL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DDHandleWDSync
|
|
//
|
|
// Moves rare WD SHM data update notifications out of the perf path.
|
|
/****************************************************************************/
|
|
void DDHandleWDSync()
|
|
{
|
|
ULONG bytesReturned;
|
|
NTSTATUS Status;
|
|
|
|
DC_BEGIN_FN("DDHandleWDSync");
|
|
|
|
// Now look for any updated fields that might be available.
|
|
if (pddShm->oe.newCapsData) {
|
|
TRC_DBG((TB, "Update for OE, %d", pddShm->oe.newCapsData));
|
|
OE_Update();
|
|
}
|
|
if (pddShm->sbc.newCapsData) {
|
|
TRC_NRM((TB, "newCapsData for SBC"));
|
|
SBC_Update(NULL);
|
|
}
|
|
if (pddShm->sbc.syncRequired) {
|
|
TRC_NRM((TB, "syncRequired for SBC"));
|
|
SBC_DDSync(FALSE);
|
|
}
|
|
if (pddShm->sbc.fClearCache) {
|
|
unsigned i;
|
|
|
|
// reset the flag
|
|
pddShm->sbc.fClearCache = FALSE;
|
|
|
|
// walk through each cache to determine if that cache
|
|
// needs to be cleared
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
|
|
if (pddShm->sbc.bitmapCacheInfo[i].fClearCache) {
|
|
TRC_NRM((TB, "clear cache with cacheID=%d", i));
|
|
|
|
// clear the entries in the cache
|
|
CH_ClearCache(pddShm->sbc.bitmapCacheInfo[i].
|
|
cacheHandle);
|
|
|
|
// reset the clear cache flag in SBC
|
|
pddShm->sbc.bitmapCacheInfo[i].fClearCache = FALSE;
|
|
}
|
|
}
|
|
|
|
// send an IOCTL to RDPWD for screen redraw
|
|
Status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_REDRAW_SCREEN,
|
|
NULL, 0, NULL, 0, &bytesReturned);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
|
|
}
|
|
}
|
|
|
|
if (pddShm->sbc.fDisableOffscreen) {
|
|
|
|
// reset the flag
|
|
pddShm->sbc.fDisableOffscreen = FALSE;
|
|
|
|
// disable offscreen rendering support
|
|
pddShm->sbc.offscreenCacheInfo.supportLevel = TS_OFFSCREEN_DEFAULT;
|
|
|
|
// send an IOCTL to RDPWD for screen redraw
|
|
Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
|
|
NULL, 0, NULL, 0, &bytesReturned);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
|
|
}
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
if (pddShm->sbc.fDisableDrawNineGrid) {
|
|
|
|
// reset the flag
|
|
pddShm->sbc.fDisableDrawNineGrid = FALSE;
|
|
|
|
// disable offscreen rendering support
|
|
pddShm->sbc.drawNineGridCacheInfo.supportLevel = TS_DRAW_NINEGRID_DEFAULT;
|
|
|
|
// send an IOCTL to RDPWD for screen redraw
|
|
Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
|
|
NULL, 0, NULL, 0, &bytesReturned);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DRAW_GDIPLUS
|
|
if (pddShm->sbc.fDisableDrawGdiplus) {
|
|
|
|
// reset the flag
|
|
pddShm->sbc.fDisableDrawGdiplus = FALSE;
|
|
|
|
// disable gdiplus support
|
|
pddShm->sbc.drawGdiplusInfo.supportLevel = TS_DRAW_GDIPLUS_DEFAULT;
|
|
|
|
// send an IOCTL to RDPWD for screen redraw
|
|
Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
|
|
NULL, 0, NULL, 0, &bytesReturned);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
// Check SSI flags.
|
|
if (pddShm->ssi.saveBitmapSizeChanged ||
|
|
pddShm->ssi.resetInterceptor) {
|
|
TRC_DBG((TB, "Update for SSI, %d:%d",
|
|
pddShm->ssi.saveBitmapSizeChanged,
|
|
pddShm->ssi.resetInterceptor));
|
|
SSI_Update(FALSE);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DrvEscape - see NT DDK documentation.
|
|
/****************************************************************************/
|
|
ULONG DrvEscape(
|
|
SURFOBJ *pso,
|
|
ULONG iEsc,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut)
|
|
{
|
|
ULONG rc = FALSE;
|
|
ULONG escCode = 0;
|
|
ULONG bytesReturned;
|
|
NTSTATUS status;
|
|
TSHARE_DD_TIMER_INFO timerInfo;
|
|
TSHARE_DD_OUTPUT_IN outputIn;
|
|
PDD_PDEV pPDev;
|
|
|
|
DC_BEGIN_FN("DrvEscape");
|
|
|
|
// DrvEscape sometimes gets called after the driver has terminated,
|
|
// especially with ESC_TIMEROBJ_SIGNALLED.
|
|
if (ddConnected) {
|
|
pPDev = (PDD_PDEV)pso->dhpdev;
|
|
|
|
// Performance path in this function is the desktop thread timer
|
|
// trigger.
|
|
if (iEsc == ESC_TIMEROBJ_SIGNALED) {
|
|
TRC_DBG((TB, "Got a timer kick - IOCtl to WD"));
|
|
TRC_ASSERT((NULL != pso), (TB, "NULL pso"));
|
|
|
|
rc = TRUE;
|
|
|
|
// Race condition: we got output (or, more likely, a timer pop)
|
|
// after a disconnect. Just ignore it.
|
|
if (NULL != pddShm) {
|
|
status = SCH_DDOutputAvailable(pPDev, TRUE);
|
|
|
|
// If this fails, either
|
|
// - the failure was in the WD, and it's up to the WD to
|
|
// correct it (or quit the session)
|
|
// - the failure was in the infrastructure carrying the
|
|
// IOCtl to the WD. There's nothing we can do in this
|
|
// case other than try on the next output call.
|
|
if (status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Error on sending output IOCtl, status %lu",
|
|
status));
|
|
}
|
|
|
|
if (!pddShm->fShmUpdate) {
|
|
DC_QUIT;
|
|
}
|
|
else {
|
|
DDHandleWDSync();
|
|
pddShm->fShmUpdate = FALSE;
|
|
}
|
|
}
|
|
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "DrvEscape %s (%d) called after DD terminated",
|
|
iEsc == QUERYESCSUPPORT ? "QUERYESCSUPPORT " :
|
|
iEsc == ESC_TIMEROBJ_SIGNALED ? "ESC_TIMEROBJ_SIGNALED" :
|
|
iEsc == ESC_SET_WD_TIMEROBJ ? "ESC_SET_WD_TIMEROBJ " :
|
|
"- Unknown -",
|
|
iEsc));
|
|
|
|
// Return FALSE for QUERYESCSUPPORT, TRUE for others (otherwise
|
|
// USER asserts).
|
|
rc = (iEsc == QUERYESCSUPPORT ? FALSE : TRUE);
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Process the non-performance-path escape codes.
|
|
switch (iEsc) {
|
|
case QUERYESCSUPPORT:
|
|
// Do we support the function? If so, mark the function as OK.
|
|
escCode = *((PUINT32)pvIn);
|
|
|
|
TRC_DBG((TB, "Query for escape code %lu", escCode));
|
|
|
|
if ((escCode == ESC_TIMEROBJ_SIGNALED) ||
|
|
(escCode == ESC_SET_WD_TIMEROBJ)) {
|
|
// Supported functions - return TRUE.
|
|
TRC_DBG((TB, "We support escape code %lu", escCode));
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
|
|
case ESC_SET_WD_TIMEROBJ:
|
|
{
|
|
DD_UPD_STATE(DD_TIMEROBJ);
|
|
|
|
// We have been given the timer details from Win32: pass them
|
|
// to the WD. Note, only allow this to occur once to prevent
|
|
// evil apps from trying to fake this call.
|
|
if (pddWdTimer == NULL) {
|
|
if (cjIn != sizeof(PKTIMER)) {
|
|
TRC_ERR((TB, "Unexpected size %lu arrived", cjIn));
|
|
}
|
|
else {
|
|
// Got the timer object OK. Save the handle here, and
|
|
// then IOCtl across to the WD to tell it the handle.
|
|
TRC_DBG((TB, "Timer object %p arrived", pvIn));
|
|
pddWdTimer = (PKTIMER)pvIn;
|
|
TRC_ASSERT((ddWdHandle != NULL), (TB, "NULL WD handle"));
|
|
|
|
timerInfo.pKickTimer = pddWdTimer;
|
|
status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_WDTS_DD_TIMER_INFO, &timerInfo,
|
|
sizeof(TSHARE_DD_TIMER_INFO), NULL, 0,
|
|
&bytesReturned);
|
|
if (status != STATUS_SUCCESS) {
|
|
TRC_ERR((TB, "Timer Info IOCtl returned %lu", status));
|
|
|
|
// Looking at the current NT code, there is NO WAY of
|
|
// reporting an error on this operation. If we return
|
|
// 0 from DrvEscape, then USER will assert. Great.
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef DC_DEBUG
|
|
// This event is generated by Bungle, a test app which displays the
|
|
// contents of the frame buffer. Here we return it the address of
|
|
// the frame buffer so it can do the displaying.
|
|
case 3:
|
|
{
|
|
ULONG cBytes;
|
|
|
|
TRC_ALT((TB, "copy frame buffer requested"));
|
|
|
|
pPDev = (PDD_PDEV)pso->dhpdev;
|
|
cBytes = (ULONG)(pPDev->cxScreen * pPDev->cyScreen);
|
|
if (cjOut != cBytes) {
|
|
TRC_ERR((TB, "Wrong memory block size"));
|
|
}
|
|
else {
|
|
memcpy(pvOut, pPDev->pFrameBuf, cBytes);
|
|
rc = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
#ifdef i386
|
|
// This event will be generated by the DbgBreak program. It forces
|
|
// us to break to the kernel debugger in the right WinStation
|
|
// context and in the DD, thus letting us set break points in a
|
|
// sensible fashion!
|
|
case 4:
|
|
TRC_ALT((TB, "break to debugger requested"));
|
|
_asm int 3;
|
|
break;
|
|
#endif
|
|
|
|
#endif // DC_DEBUG
|
|
|
|
case ESC_GET_DEVICEBITMAP_SUPPORT:
|
|
{
|
|
SIZEL bitmapSize;
|
|
|
|
if (cjIn >= sizeof(ICA_DEVICE_BITMAP_INFO)) {
|
|
|
|
if (cjOut >= sizeof(ULONG)) {
|
|
|
|
bitmapSize.cx = (*((PICA_DEVICE_BITMAP_INFO)pvIn)).cx;
|
|
bitmapSize.cy = (*((PICA_DEVICE_BITMAP_INFO)pvIn)).cy;
|
|
|
|
rc = TRUE;
|
|
|
|
if (OEDeviceBitmapCachable(pPDev, bitmapSize, pPDev->iBitmapFormat)) {
|
|
*((PULONG)pvOut) = TRUE;
|
|
}
|
|
else {
|
|
*((PULONG)pvOut) = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Wrong output block size"));
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Wrong input block size"));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TRC_ERR((TB, "Unrecognised request %lu", iEsc));
|
|
break;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvGetModes - see NT DDK documentation */
|
|
/* */
|
|
/* Returns the list of available modes for the device. */
|
|
/****************************************************************************/
|
|
ULONG DrvGetModes(HANDLE hDriver, ULONG cjSize, DEVMODEW *pdm)
|
|
{
|
|
INT32 cModes;
|
|
INT32 cbOutputSize = 0;
|
|
PVIDEO_MODE_INFORMATION pVideoModeInformation = NULL;
|
|
PVIDEO_MODE_INFORMATION pVideoTemp;
|
|
INT32 cOutputModes = cjSize / sizeof(DEVMODEW);
|
|
INT32 cbModeSize;
|
|
|
|
DC_BEGIN_FN("DrvGetModes");
|
|
|
|
TRC_NRM((TB, "DrvGetModes"));
|
|
|
|
// Get the list of valid modes.
|
|
cModes = DDGetModes(hDriver, &pVideoModeInformation, &cbModeSize);
|
|
|
|
// Should only ever return zero modes or one mode:
|
|
// If we're chained into the console session, we'll see zero modes so
|
|
// we return 0 to indicate that we will do whatever was set up in the
|
|
// registry before we got loaded. Otherwise, if we got more than one mode
|
|
// we bail out now.
|
|
if (cModes == -1) {
|
|
TRC_NRM((TB, "DrvGetModes returning 0 modes"));
|
|
ddConsole = TRUE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (cModes != 1) {
|
|
TRC_ERR((TB, "DrvGetModes failed to get mode information"));
|
|
ddConsole = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (pdm == NULL) {
|
|
// Return the size of the buffer required to receive all our modes.
|
|
cbOutputSize = cModes * sizeof(DEVMODEW);
|
|
TRC_DBG((TB, "Require %ld bytes for data", cbOutputSize));
|
|
}
|
|
else {
|
|
// Now copy the information for the supported modes back into the
|
|
// output buffer.
|
|
cbOutputSize = 0;
|
|
pVideoTemp = pVideoModeInformation;
|
|
|
|
do {
|
|
if (pVideoTemp->Length != 0) {
|
|
// Check we still have room in the buffer.
|
|
if (cOutputModes == 0) {
|
|
TRC_DBG((TB, "No more room %ld modes left", cModes));
|
|
break;
|
|
}
|
|
|
|
// Clear the structure.
|
|
memset(pdm, 0, sizeof(DEVMODEW));
|
|
|
|
// Set the name of the device to the name of the DLL.
|
|
memcpy(pdm->dmDeviceName, DD_DLL_NAME, sizeof(DD_DLL_NAME));
|
|
|
|
// Fill in the rest of the mode info.
|
|
pdm->dmSpecVersion = DM_SPECVERSION;
|
|
pdm->dmDriverVersion = DM_SPECVERSION;
|
|
pdm->dmSize = sizeof(DEVMODEW);
|
|
pdm->dmDriverExtra = 0;
|
|
|
|
pdm->dmBitsPerPel = pVideoTemp->BitsPerPlane;
|
|
pdm->dmPelsWidth = pVideoTemp->VisScreenWidth;
|
|
pdm->dmPelsHeight = pVideoTemp->VisScreenHeight;
|
|
pdm->dmDisplayFrequency = pVideoTemp->Frequency;
|
|
pdm->dmDisplayFlags = 0;
|
|
|
|
pdm->dmFields = DM_BITSPERPEL |
|
|
DM_PELSWIDTH |
|
|
DM_PELSHEIGHT |
|
|
DM_DISPLAYFREQUENCY |
|
|
DM_DISPLAYFLAGS ;
|
|
|
|
TRC_NRM((TB, "Returned mode info:"));
|
|
TRC_NRM((TB, " pdm->dmBitsPerPel: %u", pdm->dmBitsPerPel));
|
|
TRC_NRM((TB, " pdm->dmPelsWidth: %u", pdm->dmPelsWidth));
|
|
TRC_NRM((TB, " pdm->dmPelsHeight: %u", pdm->dmPelsHeight));
|
|
TRC_NRM((TB, " pdm->dmDisplayFrequency: %u",
|
|
pdm->dmDisplayFrequency));
|
|
|
|
// Go to the next DEVMODE entry in the buffer.
|
|
cOutputModes--;
|
|
|
|
pdm = (LPDEVMODEW) ( ((UINT_PTR)pdm) + sizeof(DEVMODEW));
|
|
|
|
cbOutputSize += sizeof(DEVMODEW);
|
|
}
|
|
|
|
pVideoTemp = (PVIDEO_MODE_INFORMATION)
|
|
(((PCHAR)pVideoTemp) + cbModeSize);
|
|
|
|
} while (--cModes);
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
if (pVideoModeInformation != NULL) {
|
|
TRC_DBG((TB, "Freeing mode list"));
|
|
EngFreeMem(pVideoModeInformation);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return cbOutputSize;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DrvAssertMode - see NT DDK documentation.
|
|
/****************************************************************************/
|
|
BOOL DrvAssertMode(DHPDEV dhpdev, BOOL bEnable)
|
|
{
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
BOOL bRc;
|
|
SURFOBJ *psoFrameBuf;
|
|
SURFOBJ *psoDevice;
|
|
|
|
DC_BEGIN_FN("DrvAssertMode");
|
|
|
|
TRC_NRM((TB, "pPDev %p, bEnable %d", pPDev, bEnable));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_ASSERTMODE,
|
|
dhpdev, bEnable, pddFrameBuf, ddSectionObject);
|
|
#endif
|
|
|
|
if (bEnable) {
|
|
// The surface is being re-enabled.
|
|
TRC_ALT((TB, "Enabling pPDev %p", pPDev));
|
|
|
|
// Re-associate the surface handles with the device handle.
|
|
if (!EngAssociateSurface(pPDev->hsurfFrameBuf, pPDev->hdevEng, 0)) {
|
|
TRC_ERR((TB, "Failed to associate surface %p and dev %p",
|
|
pPDev->hsurfFrameBuf, pPDev->hdevEng));
|
|
bRc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (!EngAssociateSurface(pPDev->hsurfDevice, pPDev->hdevEng,
|
|
pPDev->flHooks)) {
|
|
TRC_ERR((TB, "Failed to associate surface %p and dev %p",
|
|
pPDev->hsurfDevice, pPDev->hdevEng));
|
|
bRc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_ALT((TB, "Associated surfaces %p & %p with dev %p",
|
|
pPDev->hsurfDevice, pPDev->hsurfFrameBuf, pPDev->hdevEng));
|
|
|
|
TRC_ASSERT((pddFrameBuf != NULL), (TB, "NULL frame buffer"));
|
|
|
|
// Fixup the Frame Buffer surface object to point to the current
|
|
// Frame Buffer.
|
|
psoFrameBuf = pPDev->psoFrameBuf;
|
|
TRC_ASSERT((psoFrameBuf != NULL), (TB,"NULL psoFrameBuf"));
|
|
TRC_ASSERT((psoFrameBuf->iType == STYPE_BITMAP),
|
|
(TB, "Wrong FB surface iType, %d", psoFrameBuf->iType));
|
|
psoFrameBuf->sizlBitmap.cx = ddFrameBufX;
|
|
psoFrameBuf->sizlBitmap.cy = ddFrameBufY;
|
|
psoFrameBuf->cjBits = TS_BYTES_IN_BITMAP(ddFrameBufX,
|
|
ddFrameBufY,
|
|
ddFrameBufBpp);
|
|
psoFrameBuf->pvBits = pddFrameBuf;
|
|
psoFrameBuf->pvScan0 = pddFrameBuf;
|
|
psoFrameBuf->lDelta = TS_BYTES_IN_SCANLINE(ddFrameBufX, ddFrameBufBpp);
|
|
#ifdef DC_HICOLOR
|
|
TRC_ERR((TB, "New DD frameBufBpp %d", ddFrameBufBpp));
|
|
switch (ddFrameBufBpp) {
|
|
case 4:
|
|
psoFrameBuf->iBitmapFormat = BMF_4BPP;
|
|
break;
|
|
|
|
case 8:
|
|
psoFrameBuf->iBitmapFormat = BMF_8BPP;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
psoFrameBuf->iBitmapFormat = BMF_16BPP;
|
|
break;
|
|
|
|
case 24:
|
|
psoFrameBuf->iBitmapFormat = BMF_24BPP;
|
|
break;
|
|
|
|
default:
|
|
TRC_ERR((TB, "Unsupported frame buf bpp %u - default to 8",
|
|
ddFrameBufBpp));
|
|
psoFrameBuf->iBitmapFormat = BMF_8BPP;
|
|
break;
|
|
}
|
|
#else
|
|
psoFrameBuf->iBitmapFormat = ddFrameBufBpp == 8 ? BMF_8BPP : BMF_4BPP;
|
|
#endif
|
|
|
|
// Fixup the device surface object with the characteristics of the
|
|
// current Frame Buffer.
|
|
psoDevice = EngLockSurface(pPDev->hsurfDevice);
|
|
|
|
TRC_ASSERT((psoDevice != NULL), (TB,"Null device surfac"));
|
|
TRC_ASSERT((psoDevice->iType == STYPE_DEVICE),
|
|
(TB, "Wrong device surface iType, %d", psoDevice->iType));
|
|
TRC_ASSERT((psoDevice->pvBits == NULL),
|
|
(TB, "Device surface has bits, %p", psoDevice->pvBits));
|
|
TRC_ASSERT((psoDevice->dhsurf == (DHSURF)psoFrameBuf),
|
|
(TB, "Wrong dhSurf, expect/is %p/%p",
|
|
psoFrameBuf, psoDevice->dhsurf));
|
|
|
|
// We assert now since we should always get the same iBitmapFormat
|
|
// as 8BPP. This will change once we have 24bit color support.
|
|
// Then this needs to be looked at it and fix anything as necessary
|
|
TRC_ASSERT((psoDevice->iBitmapFormat == psoFrameBuf->iBitmapFormat),
|
|
(TB, "iBitmapFormat has changed"));
|
|
|
|
// We shouldn't change the device surface size. This has already
|
|
// been advertised to GDI, changing this will cause AV in GDI,
|
|
// since GDI has cached the surface size.
|
|
//psoDevice->sizlBitmap = psoFrameBuf->sizlBitmap;
|
|
//psoDevice->iBitmapFormat = psoFrameBuf->iBitmapFormat;
|
|
|
|
EngUnlockSurface(psoDevice);
|
|
|
|
// We should never overwrite the frame-buffer pointer or section
|
|
// object; This could cause a memory leak. If we hit this assert,
|
|
// we can investigate if this does in fact lead to a memory leak.
|
|
TRC_ASSERT(((pPDev->pFrameBuf == pddFrameBuf) &&
|
|
(pPDev->SectionObject == ddSectionObject)),
|
|
(TB, "Frame buffer or section object pointer overwritten"));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - because the above assert is not hit in stress, we
|
|
// change this case to produce an IcaBreakOnDebugger
|
|
if (pPDev->pFrameBuf != pddFrameBuf ||
|
|
pPDev->SectionObject != ddSectionObject) {
|
|
WDIcaBreakOnDebugger();
|
|
}
|
|
#endif
|
|
|
|
// Make sure the PDev points to the current Frame Buffer.
|
|
pPDev->pFrameBuf = pddFrameBuf;
|
|
TRC_ALT((TB, "Pointed PDev %p to Frame Buf %p", pPDev,
|
|
pPDev->pFrameBuf));
|
|
|
|
// Make sure the pDev points to the current SectionObject
|
|
pPDev->SectionObject = ddSectionObject;
|
|
TRC_ALT((TB, "Pointed PDev %p to Section Object %p", pPDev,
|
|
pPDev->SectionObject));
|
|
}
|
|
|
|
bRc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return bRc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: DrvDisconnect */
|
|
/* */
|
|
/* Purpose: Process a disconnect from W32 - clean up the output capture */
|
|
/* code and the connection to the WD. */
|
|
/* */
|
|
/* Returns: TRUE if all is well */
|
|
/* */
|
|
/* Params: IN - channel handle */
|
|
/* IN - file object for channel */
|
|
/* */
|
|
/* Operation: Gives all sub-components notice of the disconnect, and then */
|
|
/* IOCtls to the WD to tell it that we're going. */
|
|
/****************************************************************************/
|
|
BOOL DrvDisconnect(HANDLE channelHandle, PVOID pChannelFileObject)
|
|
{
|
|
DC_BEGIN_FN("DrvDisconnect");
|
|
|
|
TRC_NRM((TB, "DrvDisconnect called"));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_DISCONNECT,
|
|
channelHandle, pChannelFileObject, ddConnected, 0);
|
|
#endif
|
|
|
|
// Check that we're connected.
|
|
if (ddConnected) {
|
|
// Terminate the dependent components.
|
|
DDDisconnect(FALSE);
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Disconnect called when not connected"));
|
|
DD_UPD_STATE(DD_DISCONNECT_ERR);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
} /* DrvDisconnect */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: DrvConnect - see Citrix documentation/code */
|
|
/* */
|
|
/* Purpose: Called when a Winstation is first connected */
|
|
/* */
|
|
/* Returns: TRUE if all is well */
|
|
/* */
|
|
/* Params: IN - channel handle to use to IOCtl to WD */
|
|
/* IN - file object for channel - used on EngFileWrite */
|
|
/* IN - video file object */
|
|
/* IN - cache statistics memory. NB This is doc'd as OUT, but */
|
|
/* the code actually passes a ptr in. */
|
|
/* */
|
|
/* Operation: Save the key parameters */
|
|
/* */
|
|
/* Note that this function is called before DrvEnablePDEV and */
|
|
/* DrvEnableSurface, hence it is not a good place to initialize */
|
|
/* TShare components. This is done later, in DDInit, called */
|
|
/* from DrvEnableSurface. */
|
|
/****************************************************************************/
|
|
BOOL DrvConnect(
|
|
HANDLE channelHandle,
|
|
PVOID pChannelFileObject,
|
|
PVOID pVideoFileObject,
|
|
PVOID pThinWireCache)
|
|
{
|
|
PCACHE_STATISTICS pPerformanceCounters;
|
|
|
|
DC_BEGIN_FN("DrvConnect");
|
|
|
|
TRC_NRM((TB, "DrvConnect"));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_CONNECT,
|
|
channelHandle, pChannelFileObject, pVideoFileObject, pThinWireCache);
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Check for sensible values - the chained DD could get loaded other */
|
|
/* than on a connect call */
|
|
/************************************************************************/
|
|
if ((channelHandle == NULL) ||
|
|
(pChannelFileObject == NULL) ||
|
|
(pVideoFileObject == NULL) ||
|
|
(pThinWireCache == NULL)) {
|
|
TRC_ERR((TB, "Null input params"));
|
|
|
|
#ifdef DC_DEBUG
|
|
TRC_ALT((TB, "But load anyway!"));
|
|
return TRUE;
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
if (ddState & DD_DISCONNECT_OUT)
|
|
DD_SET_STATE(DD_WAS_DISCONNECTED);
|
|
DD_UPD_STATE(DD_CONNECT);
|
|
#endif
|
|
|
|
// Save the channel handle, and perf counters for later - the other
|
|
// params are currently not needed.
|
|
ddWdHandle = pChannelFileObject;
|
|
pPerformanceCounters = pThinWireCache;
|
|
pPerformanceCounters->ProtocolType = PROTOCOL_ICA;
|
|
pPerformanceCounters->Length = sizeof(ICA_CACHE);
|
|
pddCacheStats = pPerformanceCounters->Specific.IcaCacheStats.ThinWireCache;
|
|
|
|
// Note that init is pending.
|
|
ddInitPending = TRUE;
|
|
|
|
// Note that we're connected.
|
|
ddConnected = TRUE;
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
} /* DrvConnect */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: DrvReconnect */
|
|
/* */
|
|
/* Pass the IOCtl to the WD, and save off the returned values, as on */
|
|
/* connect. */
|
|
/****************************************************************************/
|
|
BOOL DrvReconnect(HANDLE channelHandle, PVOID pChannelFileObject)
|
|
{
|
|
BOOL rc;
|
|
|
|
DC_BEGIN_FN("DrvReconnect");
|
|
|
|
TRC_NRM((TB, "DrvReconnect"));
|
|
|
|
#ifdef DC_DEBUG
|
|
// NT BUG 539912 - track calls to DD fns.
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_RECONNECT,
|
|
channelHandle, pChannelFileObject, ddConnected, ddConsole);
|
|
#endif
|
|
|
|
// In case the dd has not been unloaded at the end of the previous
|
|
// console shadow, we're getting called to handle this.
|
|
if (ddConsole && ddConnected) {
|
|
// no need to reconnect
|
|
rc = TRUE;
|
|
TRC_ASSERT((ddWdHandle == pChannelFileObject),
|
|
(TB,"Reconnecting with different WD handle for Console Shadow)"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
if (ddState & DD_DISCONNECT_OUT)
|
|
DD_SET_STATE(DD_WAS_DISCONNECTED);
|
|
DD_UPD_STATE(DD_RECONNECT_IN);
|
|
#endif
|
|
|
|
// Save the channel handle for later - the other params are currently
|
|
// not needed.
|
|
ddWdHandle = pChannelFileObject;
|
|
|
|
// Note that we're connected. Do this whether we reconnect
|
|
// successfully or not, as DrvDisconnect is called if we fail to */
|
|
// reconnect.
|
|
ddConnected = TRUE;
|
|
|
|
// Reinitialize RDPDD.
|
|
rc = DDInit(NULL, TRUE, ddConsole?TRUE: FALSE, NULL, 0);
|
|
if (!rc) {
|
|
TRC_ERR((TB, "Failed to reinitialize DD"));
|
|
}
|
|
|
|
DD_UPD_STATE(DD_RECONNECT_OUT);
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
} /* DrvReconnect */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvResetPDEV - see NT DDK documentation */
|
|
/* */
|
|
/* Allows us to reject dynamic screen changes if necessary */
|
|
/****************************************************************************/
|
|
BOOL DrvResetPDEV(DHPDEV dhpdevOld, DHPDEV dhpdevNew)
|
|
{
|
|
BOOL rc = TRUE;
|
|
ULONG bytesReturned;
|
|
NTSTATUS Status;
|
|
ICA_CHANNEL_END_SHADOW_DATA Data;
|
|
|
|
DC_BEGIN_FN("DrvResetPDEV");
|
|
|
|
// On the console, we can only allow the display driver to change modes
|
|
// while the connection is not up.
|
|
if (ddConsole && ddConnected) {
|
|
TRC_ALT((TB, "Mode change during console shadow: ending console shadow now"));
|
|
|
|
Data.StatusCode = STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE;
|
|
Data.bLogError = TRUE;
|
|
|
|
Status = EngFileIoControl(ddWdHandle,
|
|
IOCTL_ICA_CHANNEL_END_SHADOW,
|
|
&Data, sizeof(Data),
|
|
NULL, 0,
|
|
&bytesReturned);
|
|
}
|
|
else {
|
|
TRC_ALT((TB, "Allowing mode change"));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvGetDirectDrawInfo - see NT DDK documentation. */
|
|
/* */
|
|
/* Function called by DirectDraw to returns the capabilities of the */
|
|
/* graphics hardware */
|
|
/* */
|
|
/****************************************************************************/
|
|
BOOL
|
|
DrvGetDirectDrawInfo(
|
|
DHPDEV dhpdev,
|
|
DD_HALINFO* pHalInfo,
|
|
DWORD* pdwNumHeaps,
|
|
VIDEOMEMORY* pvmList, // Will be NULL on first call
|
|
DWORD* pdwNumFourCC,
|
|
DWORD* pdwFourCC) // Will be NULL on first call
|
|
{
|
|
BOOL rc = TRUE;
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
BOOL bCanFlip=0;
|
|
|
|
DC_BEGIN_FN("DrvGetDirectDrawInfo");
|
|
|
|
TRC_NRM((TB, "DrvGetDirectDrawInfo"));
|
|
|
|
// DirectDraw only supports 8, 16, 24 or 32 bpp
|
|
if ( (8 != pPDev->cClientBitsPerPel) &&
|
|
(16 != pPDev->cClientBitsPerPel) &&
|
|
(24 != pPDev->cClientBitsPerPel) &&
|
|
(32 != pPDev->cClientBitsPerPel) )
|
|
{
|
|
rc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
// DirectDraw is not supported if our frame buffer is not allocated as
|
|
// section mem.
|
|
if (pPDev->SectionObject == NULL) {
|
|
TRC_ERR((TB, "The section object is null."));
|
|
rc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
|
|
pHalInfo->dwSize = sizeof(*pHalInfo);
|
|
|
|
// Current primary surface attributes. Since HalInfo is zero-initialized
|
|
// by GDI, we only have to fill in the fields which should be non-zero:
|
|
|
|
pHalInfo->vmiData.pvPrimary = pPDev->pFrameBuf;
|
|
pHalInfo->vmiData.dwDisplayWidth = pPDev->cxScreen;
|
|
pHalInfo->vmiData.dwDisplayHeight = pPDev->cyScreen;
|
|
pHalInfo->vmiData.lDisplayPitch = pPDev->psoFrameBuf->lDelta;
|
|
|
|
pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
|
|
pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
|
|
pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = pPDev->cClientBitsPerPel;
|
|
|
|
if (pPDev->iBitmapFormat == BMF_8BPP)
|
|
{
|
|
pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
|
|
}
|
|
|
|
// These masks will be zero at 8bpp:
|
|
|
|
pHalInfo->vmiData.ddpfDisplay.dwRBitMask = pPDev->flRed;
|
|
pHalInfo->vmiData.ddpfDisplay.dwGBitMask = pPDev->flGreen;
|
|
pHalInfo->vmiData.ddpfDisplay.dwBBitMask = pPDev->flBlue;
|
|
|
|
if (pPDev->iBitmapFormat == BMF_32BPP)
|
|
{
|
|
pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask
|
|
= ~(pPDev->flRed | pPDev->flGreen | pPDev->flBlue);
|
|
}
|
|
else
|
|
{
|
|
pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = 0;
|
|
}
|
|
|
|
//We don't support flip
|
|
bCanFlip = FALSE;
|
|
|
|
// We don't have any video memory for offscreen use
|
|
*pdwNumHeaps = 0;
|
|
|
|
// Capabilities supported:
|
|
pHalInfo->ddCaps.dwFXCaps = 0;
|
|
|
|
// No hardware support
|
|
pHalInfo->ddCaps.dwCaps = DDCAPS_NOHARDWARE;
|
|
|
|
pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
|
|
if (bCanFlip)
|
|
{
|
|
pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
|
|
}
|
|
|
|
// FourCCs supported:
|
|
|
|
*pdwNumFourCC = 0;
|
|
// We see rdpdd passes 4bpp to directx in stress, which it does't support
|
|
// so we assert here
|
|
TRC_ASSERT(((pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount != 4) &&
|
|
(pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount != 15)),
|
|
(TB, "RDPDD shoould not pass bpp %d to DirectX",
|
|
pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount));
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* DrvEnableDirectDraw - see NT DDK documentation. */
|
|
/* */
|
|
/* GDI calls DrvEnableDirectDraw to obtain pointers to the DirectDraw */
|
|
/* callbacks that the driver supports. */
|
|
/* */
|
|
/****************************************************************************/
|
|
BOOL DrvEnableDirectDraw(
|
|
DHPDEV dhpdev,
|
|
DD_CALLBACKS* pCallBacks,
|
|
DD_SURFACECALLBACKS* pSurfaceCallBacks,
|
|
DD_PALETTECALLBACKS* pPaletteCallBacks)
|
|
{
|
|
BOOL rc = TRUE;
|
|
PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
|
|
|
|
DC_BEGIN_FN("DrvEnableDirectDraw");
|
|
|
|
TRC_NRM((TB, "DrvEnableDirectDraw"));
|
|
|
|
#ifdef DC_DEBUG
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_ENABLEDIRECTDRAW,
|
|
0, 0, pPDev->SectionObject, ddSectionObject);
|
|
#endif
|
|
|
|
// DirectDraw is not supported if our frame buffer is not allocated as
|
|
// section mem.
|
|
if (pPDev->SectionObject == NULL ) {
|
|
TRC_ERR((TB, "The section object is NULL!"));
|
|
rc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
pCallBacks->MapMemory = DdMapMemory;
|
|
pCallBacks->dwFlags = DDHAL_CB32_MAPMEMORY;
|
|
|
|
pSurfaceCallBacks->Lock = DdLock;
|
|
pSurfaceCallBacks->Unlock = DdUnlock;
|
|
pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_LOCK
|
|
| DDHAL_SURFCB32_UNLOCK;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DrvDisableDirectDraw - see NT DDK documentation. */
|
|
/* */
|
|
/****************************************************************************/
|
|
VOID DrvDisableDirectDraw(
|
|
DHPDEV dhpdev)
|
|
{
|
|
DC_BEGIN_FN("DrvDisableDirectDraw");
|
|
|
|
TRC_NRM((TB, "DrvDisableDirectDraw"));
|
|
|
|
#ifdef DC_DEBUG
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_DISABLEDIRECTDRAW,
|
|
0, 0, 0, ddSectionObject);
|
|
#endif
|
|
|
|
//Do nothing here
|
|
|
|
DC_END_FN();
|
|
}
|