2025-04-27 07:49:33 -04:00

723 lines
20 KiB
C

/******************************Module*Header*******************************\
* Module Name: enable.c
*
* Functions to enable and disable the driver
*
* Copyright (c) 1992-1995 Microsoft Corporation
\**************************************************************************/
#include "driver.h"
extern GDIINFO gaulCap; // in gdiinfo.c
extern LOGPALETTE logPalVGA; // in gdiinfo.c
extern DEVINFO devinfoVGA; // in gdiinfo.c
extern LPBYTE pPtrSave;
extern LPBYTE pPtrWork;
BOOL SetUpBanking(PDEVSURF, PPDEV);
BOOL bInitPointer(PPDEV);
extern ajConvertBuffer[1]; // Arbitrary sized array!
static DRVFN gadrvfn[] = {
{ INDEX_DrvEnablePDEV, (PFN) DrvEnablePDEV },
{ INDEX_DrvCompletePDEV, (PFN) DrvCompletePDEV },
{ INDEX_DrvDisablePDEV, (PFN) DrvDisablePDEV },
{ INDEX_DrvEnableSurface, (PFN) DrvEnableSurface },
{ INDEX_DrvDisableSurface, (PFN) DrvDisableSurface },
{ INDEX_DrvRealizeBrush, (PFN) DrvRealizeBrush },
{ INDEX_DrvCreateDeviceBitmap, (PFN) DrvCreateDeviceBitmap },
{ INDEX_DrvDeleteDeviceBitmap, (PFN) DrvDeleteDeviceBitmap },
{ INDEX_DrvBitBlt, (PFN) DrvBitBlt },
{ INDEX_DrvTextOut, (PFN) DrvTextOut },
{ INDEX_DrvSetPointerShape, (PFN) DrvSetPointerShape },
{ INDEX_DrvMovePointer, (PFN) DrvMovePointer },
{ INDEX_DrvStrokePath, (PFN) DrvStrokePath },
{ INDEX_DrvCopyBits, (PFN) DrvCopyBits },
{ INDEX_DrvDitherColor, (PFN) DrvDitherColor },
{ INDEX_DrvAssertMode, (PFN) DrvAssertMode },
{ INDEX_DrvSaveScreenBits, (PFN) DrvSaveScreenBits },
{ INDEX_DrvGetModes, (PFN) DrvGetModes },
{ INDEX_DrvFillPath, (PFN) DrvFillPath },
{ INDEX_DrvPaint, (PFN) DrvPaint }
};
/******************************Public*Routine******************************\
* BOOL bEnableDriver(iEngineVersion, cb, pded)
*
* Enables the driver by filling the function table. This call is made by
* the Engine to fill its driver function table in the LDEV (Logical DEVice).
* This call should only be made once per driver but we can handle being
* called multiple times.
*
\**************************************************************************/
BOOL DrvEnableDriver
(
ULONG iEngineVersion,
ULONG cb,
PDRVENABLEDATA pded
)
{
DISPDBG((2, "enabling Driver\n"));
cb /= sizeof(ULONG);
switch(cb)
{
case 3:
pded->pdrvfn = gadrvfn;
case 2:
pded->c = sizeof(gadrvfn) / sizeof(DRVFN);
case 1:
pded->iDriverVersion = DDI_DRIVER_VERSION_NT4;
}
return(TRUE);
}
/******************************Public*Routine******************************\
* DHPDEV DrvEnablePDEV
*
* Enable the Physical DEVice
*
* Warnings:
* The PDEV isn't complete until bCompletePDEV is called.
*
\**************************************************************************/
DHPDEV DrvEnablePDEV
(
DEVMODEW *pdrivw,
PWSTR pwszLogAddress,
ULONG cPatterns,
HSURF *ahsurfPatterns,
ULONG cjGdiInfo,
ULONG *pdevcaps,
ULONG cb,
PDEVINFO pdevinfo,
HDEV hdev, // HDEV, used for callbacks
PWSTR pwszDeviceName,
HANDLE hDriver // Handle to base driver
)
{
PPDEV ppdev;
DISPDBG((2, "enabling PDEV\n"));
//
// Define flag to keep track of allocation
//
ppdev = (PPDEV) EngAllocMem(0, sizeof(PDEV), ALLOC_TAG);
if (ppdev == NULL)
{
goto errorAllocPDEV;
}
memset(ppdev, 0, sizeof(PDEV));
//
// Identifier, for debugging purposes
//
ppdev->ident = PDEV_IDENT;
//
// Cache the device driver handle away for later use.
//
ppdev->hDriver = hDriver;
//
// Initialize the cursor stuff. We can violate the atomic rule here
// since nobody can talk to the driver yet.
//
ppdev->xyCursor.x = 320; // Non-atomic
ppdev->xyCursor.y = 240; // Non-atomic
ppdev->ptlExtent.x = 0;
ppdev->ptlExtent.y = 0;
ppdev->cExtent = 0;
ppdev->flCursor = CURSOR_DOWN;
//
// Get the current screen mode information. Set up device caps and devinfo.
//
if (!bInitPDEV(ppdev, pdrivw, &gaulCap, NULL))
{
DISPDBG((1, "DrvEnablePDEV failed bInitPDEV\n"));
goto errorbInitPDEV;
}
cjGdiInfo=min(cjGdiInfo, sizeof(GDIINFO));
memcpy(pdevcaps, &gaulCap, cjGdiInfo);
// Now let's pass back the devinfo
ppdev->hpalDefault = EngCreatePalette(PAL_INDEXED, 16,
(PULONG) (logPalVGA.palPalEntry),
0, 0, 0);
if (ppdev->hpalDefault == (HPALETTE) 0)
{
goto errorEngCreatePalette;
}
*pdevinfo = devinfoVGA;
pdevinfo->hpalDefault = ppdev->hpalDefault;
// Try to preallocate a saved screen bits buffer. If we fail, set the flag
// to indicate the buffer is in use, so that we'll never attempt to use it.
// If we succeed, mark the buffer as free.
if ((ppdev->pjPreallocSSBBuffer = (PUCHAR)
EngAllocMem(0, PREALLOC_SSB_SIZE, ALLOC_TAG)) != NULL)
{
ppdev->flPreallocSSBBufferInUse = FALSE;
ppdev->ulPreallocSSBSize = PREALLOC_SSB_SIZE;
}
else
{
ppdev->flPreallocSSBBufferInUse = TRUE;
}
// Fill in the DIB4->VGA conversion tables. Allow 256 extra bytes so that
// we can always safely align the tables to a 256-byte boundary, for
// look-up reasons. There are four tables, each 256 bytes long
ppdev->pucDIB4ToVGAConvBuffer =
(UCHAR *) EngAllocMem(0, (256*4+256)*sizeof(UCHAR), ALLOC_TAG);
if (ppdev->pucDIB4ToVGAConvBuffer == NULL)
{
goto errorAllocpucDIB4ToVGAConvBuffer;
}
// Round the table start up to the nearest 256 byte boundary, because the
// tables must start on 256-byte boundaries for look-up reasons
ppdev->pucDIB4ToVGAConvTables =
(UCHAR *) ((ULONG) (ppdev->pucDIB4ToVGAConvBuffer + 0xFF) & ~0xFF);
vSetDIB4ToVGATables(ppdev->pucDIB4ToVGAConvTables);
return((DHPDEV) ppdev);
errorAllocpucDIB4ToVGAConvBuffer:
//
// Free the preallocated saved screen bits buffer, if there is one.
//
if (ppdev->pjPreallocSSBBuffer != NULL)
{
EngFreeMem(ppdev->pjPreallocSSBBuffer);
}
EngDeletePalette(ppdev->hpalDefault);
errorEngCreatePalette:
errorbInitPDEV:
EngFreeMem(ppdev);
errorAllocPDEV:
return((DHPDEV) 0);
UNREFERENCED_PARAMETER(cb);
UNREFERENCED_PARAMETER(pwszLogAddress);
UNREFERENCED_PARAMETER(pwszDeviceName);
}
/******************************Public*Routine******************************\
* BOOL bCompletePDEV(dhpdev, hpdev)
*
* Complete the initialization of the PDEV
*
\**************************************************************************/
VOID DrvCompletePDEV(
DHPDEV dhpdev,
HDEV hdev)
{
PPDEV ppdev;
ppdev = (PPDEV) dhpdev;
ppdev->hdevEng = hdev;
}
/******************************Public*Routine******************************\
* VOID DrvDisablePDEV(dhpdev)
*
* Shutdown this physical device.
*
* Warnings:
* If a surface is still active for this PDEV it will be freed.
*
\**************************************************************************/
VOID DrvDisablePDEV(DHPDEV dhpdev)
{
PPDEV ppdev;
ppdev = (PPDEV) dhpdev;
DISPDBG((2, "disabling PDEV\n"));
EngDeletePalette(ppdev->hpalDefault);
// Free the preallocated saved screen bits buffer, if there is one.
if (ppdev->pjPreallocSSBBuffer != NULL)
{
EngFreeMem(ppdev->pjPreallocSSBBuffer);
}
// Free the conversion table buffer
if (ppdev->pucDIB4ToVGAConvBuffer != NULL)
{
EngFreeMem(ppdev->pucDIB4ToVGAConvBuffer);
}
// Delete the PDEV
EngFreeMem(dhpdev);
DISPDBG((2, "disabled PDEV\n"));
}
/******************************Public*Routine******************************\
* HSURF DrvEnableSurface(dhpdev)
*
* Enable the surface for the device. This will actually intialize the
* screen on the VGA.
*
* Warnings:
* This routine should only be called ONCE per PDEV.
*
\**************************************************************************/
HSURF DrvEnableSurface(DHPDEV dhpdev)
{
PPDEV ppdev;
PDEVSURF pdsurf;
DHSURF dhsurf;
HSURF hsurf;
DISPDBG((2, "enabling Surface\n"));
ppdev = (PPDEV) dhpdev;
//
// Initialize the VGA device into the selected mode which will also map
// the video frame buffer
//
if (!bInitVGA(ppdev, TRUE))
{
goto error_done;
}
dhsurf = (DHSURF) EngAllocMem(0, sizeof(DEVSURF), ALLOC_TAG);
if (dhsurf == (DHSURF) 0)
{
goto error_done;
}
pdsurf = (PDEVSURF) dhsurf;
pdsurf->ident = DEVSURF_IDENT;
pdsurf->flSurf = 0;
pdsurf->iFormat = BMF_PHYSDEVICE;
pdsurf->jReserved1 = 0;
pdsurf->jReserved2 = 0;
pdsurf->ppdev = ppdev;
pdsurf->sizlSurf.cx = ppdev->sizlSurf.cx;
pdsurf->sizlSurf.cy = ppdev->sizlSurf.cy;
pdsurf->lNextPlane = 0;
pdsurf->pvScan0 = ppdev->pjScreen;
pdsurf->pvBitmapStart = ppdev->pjScreen;
pdsurf->pvStart = ppdev->pjScreen;
pdsurf->pvConv = &ajConvertBuffer[0];
// Initialize pointer information.
//
// bInitPointer must be called before bInitSavedBits.
//
if (!bInitPointer(ppdev)) {
DISPDBG((0, "DrvEnablePDEV failed bInitPointer\n"));
goto error_clean;
}
if (!SetUpBanking(pdsurf, ppdev)) {
DISPDBG((0, "DrvEnablePDEV failed SetUpBanking\n"));
goto error_clean;
}
if ((hsurf = EngCreateDeviceSurface(dhsurf, ppdev->sizlSurf, BMF_4BPP)) ==
(HSURF) 0)
{
DISPDBG((0, "DrvEnablePDEV failed EngCreateDeviceSurface\n"));
goto error_clean;
}
//
// vInitSavedBits must be called after bInitPointer.
//
vInitSavedBits(ppdev);
if (EngAssociateSurface(hsurf, ppdev->hdevEng,
HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH |
HOOK_COPYBITS | HOOK_PAINT | HOOK_FILLPATH
))
{
ppdev->hsurfEng = hsurf;
ppdev->pdsurf = pdsurf;
// Set up an empty saved screen block list
pdsurf->ssbList = NULL;
DISPDBG((2, "enabled surface\n"));
return(hsurf);
}
DISPDBG((0, "DrvEnablePDEV failed EngDeleteSurface\n"));
EngDeleteSurface(hsurf);
error_clean:
// We created the surface, so delete it
EngFreeMem(dhsurf);
error_done:
return((HSURF) 0);
}
/******************************Public*Routine******************************\
* DrvDisableSurface
*
* Free resources associated with this surface.
*
\**************************************************************************/
VOID DrvDisableSurface(DHPDEV dhpdev)
{
PPDEV ppdev = (PPDEV) dhpdev;
PDEVSURF pdsurf = ppdev->pdsurf;
PSAVED_SCREEN_BITS pSSB, pSSBNext;
DISPDBG((2, "disabling surface\n"));
// Free up banking-related stuff.
EngFreeMem(pdsurf->pBankSelectInfo);
if (pdsurf->pbiBankInfo != NULL) {
EngFreeMem(pdsurf->pbiBankInfo);
}
if (pdsurf->pbiBankInfo2RW != NULL) {
EngFreeMem(pdsurf->pbiBankInfo2RW);
}
if (pdsurf->pvBankBufferPlane0 != NULL) {
EngFreeMem(pdsurf->pvBankBufferPlane0);
}
if (ppdev->pPointerAttributes != NULL) {
EngFreeMem(ppdev->pPointerAttributes);
}
// Free any pending saved screen bit blocks.
pSSB = pdsurf->ssbList;
while (pSSB != (PSAVED_SCREEN_BITS) NULL) {
//
// Point to the next saved screen bits block
//
pSSBNext = (PSAVED_SCREEN_BITS) pSSB->pvNextSSB;
//
// Free the current block
//
EngFreeMem(pSSB);
pSSB = pSSBNext;
}
EngDeleteSurface((HSURF) ppdev->hsurfEng);
EngFreeMem(pdsurf); // free the surface
DISPDBG((2, "disabled surface\n"));
}
/******************************Public*Routine******************************\
* DrvAssertMode
*
* Ping the device back into its last known mode
*
\**************************************************************************/
BOOL DrvAssertMode(DHPDEV dhpdev, BOOL Enable)
{
PPDEV ppdev = (PPDEV) dhpdev;
ULONG returnedDataLength;
DISPDBG((2, "DrvAssertMode\n"));
if (Enable) {
//
// The screen must be reenabled since we had gone to full screen,
// or another pdev.
// Re-initialize the device.
//
pPtrSave = ppdev->pPtrSave;
pPtrWork = ppdev->pPtrWork;
if (!bInitVGA(ppdev, FALSE))
{
RIP("DrvAssertMode failed bInitVGA\n");
return FALSE;
}
vForceBank0(ppdev);
// Restore the off screen data. This protects the Desktop
// from a DOS application that might trash the off screen
// memory.
ppdev->bBitsSaved = FALSE; // clear the DrvSaveScreenBits info flag
// ie. blow away cached screen region
} else {
//
// We must give up the display.
// Call the kernel driver to reset the device to a known state.
//
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_RESET_DEVICE,
NULL,
0,
NULL,
0,
&returnedDataLength))
{
RIP("Reset Device Failed");
return FALSE;
}
}
return TRUE;
}
/******************************Public*Routine******************************\
* DrvGetModes
*
* Returns the list of available modes for the device.
*
\**************************************************************************/
ULONG DrvGetModes(
HANDLE hDriver,
ULONG cjSize,
DEVMODEW *pdm)
{
DWORD cModes;
DWORD cbOutputSize;
PVIDEO_MODE_INFORMATION pVideoModeInformation, pVideoTemp;
DWORD cOutputModes = cjSize / (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
DWORD cbModeSize;
DISPDBG((2, "DrvGetModes\n"));
cModes = getAvailableModes(hDriver,
(PVIDEO_MODE_INFORMATION *) &pVideoModeInformation,
&cbModeSize);
if (cModes == 0)
{
DISPDBG((0, "DrvGetModes failed to get mode information"));
return 0;
}
if (pdm == NULL)
{
cbOutputSize = cModes * (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
}
else
{
//
// Now copy the information for the supported modes back into the output
// buffer
//
cbOutputSize = 0;
pVideoTemp = pVideoModeInformation;
do
{
if (pVideoTemp->Length != 0)
{
if (cOutputModes == 0)
{
break;
}
//
// Zero the entire structure to start off with.
//
memset(pdm, 0, sizeof(DEVMODEW));
//
// Set the name of the device to the name of the DLL.
//
memcpy(pdm->dmDeviceName, DLL_NAME, sizeof(DLL_NAME));
pdm->dmSpecVersion = DM_SPECVERSION;
pdm->dmDriverVersion = DM_SPECVERSION;
pdm->dmSize = sizeof(DEVMODEW);
pdm->dmDriverExtra = DRIVER_EXTRA_SIZE;
pdm->dmBitsPerPel = pVideoTemp->NumberOfPlanes *
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 ;
//
// Go to the next DEVMODE entry in the buffer.
//
cOutputModes--;
pdm = (LPDEVMODEW) ( ((ULONG)pdm) + sizeof(DEVMODEW) +
DRIVER_EXTRA_SIZE);
cbOutputSize += (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
}
pVideoTemp = (PVIDEO_MODE_INFORMATION)
(((PUCHAR)pVideoTemp) + cbModeSize);
} while (--cModes);
}
EngFreeMem(pVideoModeInformation);
return cbOutputSize;
}
/******************************Public*Routine******************************\
* VOID vInitSavedBits(ppdev)
*
* Initializes saved bits structures. Must be done after bank
* initialization and vInitBrushCache.
*
\**************************************************************************/
VOID vInitSavedBits(PPDEV ppdev)
{
if (!(ppdev->fl & DRIVER_OFFSCREEN_REFRESHED))
{
return;
}
//
// set up rect to right of visible screen
//
ppdev->rclSavedBitsRight.left = ppdev->sizlSurf.cx;
ppdev->rclSavedBitsRight.top = 0;
ppdev->rclSavedBitsRight.right = ppdev->sizlMem.cx-PLANAR_PELS_PER_CPU_ADDRESS;
ppdev->rclSavedBitsRight.bottom = ppdev->sizlSurf.cy;
if ((ppdev->rclSavedBitsRight.right <= ppdev->rclSavedBitsRight.left) ||
(ppdev->rclSavedBitsRight.bottom <= ppdev->rclSavedBitsRight.top))
{
ppdev->rclSavedBitsRight.left = 0;
ppdev->rclSavedBitsRight.top = 0;
ppdev->rclSavedBitsRight.right = 0;
ppdev->rclSavedBitsRight.bottom = 0;
}
//
// set up rect below visible screen
//
ppdev->rclSavedBitsBottom.left = 0;
ppdev->rclSavedBitsBottom.top = ppdev->sizlSurf.cy;
ppdev->rclSavedBitsBottom.right = ppdev->sizlMem.cx-PLANAR_PELS_PER_CPU_ADDRESS;
ppdev->rclSavedBitsBottom.bottom = ppdev->sizlMem.cy - ppdev->cNumScansUsedByPointer;
if ((ppdev->rclSavedBitsBottom.right <= ppdev->rclSavedBitsBottom.left) ||
(ppdev->rclSavedBitsBottom.bottom <= ppdev->rclSavedBitsBottom.top))
{
ppdev->rclSavedBitsBottom.left = 0;
ppdev->rclSavedBitsBottom.top = 0;
ppdev->rclSavedBitsBottom.right = 0;
ppdev->rclSavedBitsBottom.bottom = 0;
}
DISPDBG((1,"rclSavedBitsRight: (%4x,%4x,%4x,%4x)\n",
ppdev->rclSavedBitsRight.left,
ppdev->rclSavedBitsRight.top,
ppdev->rclSavedBitsRight.right,
ppdev->rclSavedBitsRight.bottom
));
DISPDBG((1,"rclSavedBitsBottom: (%4x,%4x,%4x,%4x)\n",
ppdev->rclSavedBitsBottom.left,
ppdev->rclSavedBitsBottom.top,
ppdev->rclSavedBitsBottom.right,
ppdev->rclSavedBitsBottom.bottom
));
//
// NOTE: we have subtracted one DWORD from the right edge. This is because
// later it is assumed that we can align by right shifting by up to
// one DWORD (unless of course, the width of the buffer is 0).
//
ppdev->bBitsSaved = FALSE;
return;
}