/******************************Module*Header*******************************\ * Module Name: pointer.c * * This module contains the hardware pointer support for the display * driver. * * Copyright (c) 1994-1995 Microsoft Corporation \**************************************************************************/ #include "precomp.h" // This should match the miniport definition: #define VIDEO_MODE_LOCAL_POINTER 0x08 // Look-up table for masking the right edge of the given pointer bitmap: BYTE gajMask[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFc, 0xFE }; /******************************Public*Routine******************************\ * VOID DrvMovePointer * * NOTE: Because we have set GCAPS_ASYNCMOVE, this call may occur at any * time, even while we're executing another drawing call! * * Consequently, we have to explicitly synchronize any shared * resources. In our case, since we touch the CRTC register here * and in the banking code, we synchronize access using a critical * section. * \**************************************************************************/ VOID DrvMovePointer( SURFOBJ* pso, LONG x, LONG y, RECTL* prcl) { VIDEO_POINTER_POSITION Position; PDEV* ppdev; DWORD returnedDataLength; ppdev = (PDEV*) pso->dhpdev; #if MULTI_BOARDS { if (x != -1) { OH* poh; poh = ((DSURF*) pso->dhsurf)->poh; x += poh->x; y += poh->y; } } #endif if (x == -1) { ppdev->bPointerEnabled = FALSE; EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_DISABLE_POINTER, NULL, 0, NULL, 0, &returnedDataLength); } else { Position.Column = (short) (x - ppdev->ptlHotSpot.x); Position.Row = (short) (y - ppdev->ptlHotSpot.y); if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_LOCAL_POINTER) { // This is rather dumb: IO_CURSOR_X(ppdev, ppdev->pjIoBase, Position.Column + CURSOR_CX); IO_CURSOR_Y(ppdev, ppdev->pjIoBase, Position.Row + CURSOR_CY); } else { EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_POINTER_POSITION, &Position, sizeof(VIDEO_POINTER_POSITION), NULL, 0, &returnedDataLength); } // Don't forget to turn on the pointer, if it was off: if (!ppdev->bPointerEnabled) { ppdev->bPointerEnabled = TRUE; EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_ENABLE_POINTER, NULL, 0, NULL, 0, &returnedDataLength); } } } /******************************Public*Routine******************************\ * VOID DrvSetPointerShape * * Sets the new pointer shape. * \**************************************************************************/ ULONG DrvSetPointerShape( SURFOBJ* pso, SURFOBJ* psoMsk, SURFOBJ* psoColor, XLATEOBJ* pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL* prcl, FLONG fl) { VIDEO_POINTER_ATTRIBUTES* pPointerAttributes; PDEV* ppdev; ULONG cx; ULONG cy; LONG cjWhole; LONG cjDst; BYTE* pjSrc; BYTE* pjDst; LONG lSrcDelta; LONG lDstDelta; LONG i; DWORD returnedDataLength; ppdev = (PDEV*) pso->dhpdev; pPointerAttributes = ppdev->pPointerAttributes; if (pPointerAttributes == NULL) { // There are no hardware pointer capabilities: return(SPS_DECLINE); } cx = psoMsk->sizlBitmap.cx; cy = psoMsk->sizlBitmap.cy / 2; if ((cx > ppdev->PointerCapabilities.MaxWidth) || (cy > ppdev->PointerCapabilities.MaxHeight) || (psoColor != NULL) || !(fl & SPS_CHANGE) || (cx & 0x7)) { goto HideAndDecline; } #if MULTI_BOARDS { if (x != -1) { OH* poh; poh = ((DSURF*) pso->dhsurf)->poh; x += poh->x; y += poh->y; } } #endif cjWhole = cx / 8; cjDst = pPointerAttributes->WidthInBytes * pPointerAttributes->Height; // Copy AND bits: pjSrc = psoMsk->pvScan0; lSrcDelta = psoMsk->lDelta; pjDst = pPointerAttributes->Pixels; lDstDelta = pPointerAttributes->WidthInBytes; memset(pjDst, -1, cjDst); // Pad unused AND bits for (i = cy; i != 0; i--) { memcpy(pjDst, pjSrc, cjWhole); pjSrc += lSrcDelta; pjDst += lDstDelta; } // Copy XOR bits: pjDst = pPointerAttributes->Pixels + ppdev->cjXorMaskStartOffset; memset(pjDst, 0, cjDst); // Pad unused XOR bits for (i = cy; i != 0; i--) { memcpy(pjDst, pjSrc, cjWhole); pjSrc += lSrcDelta; pjDst += lDstDelta; } // Initialize the pointer attributes: ppdev->ptlHotSpot.x = xHot; ppdev->ptlHotSpot.y = yHot; pPointerAttributes->Column = (short) (x - xHot); pPointerAttributes->Row = (short) (y - yHot); pPointerAttributes->Enable = (x != -1); pPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER; if (fl & SPS_ANIMATESTART) pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START; else if (fl & SPS_ANIMATEUPDATE) pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE; if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_LOCAL_POINTER) { // This is rather dumb: IO_CURSOR_X(ppdev, ppdev->pjIoBase, pPointerAttributes->Column + CURSOR_CX); IO_CURSOR_Y(ppdev, ppdev->pjIoBase, pPointerAttributes->Row + CURSOR_CY); } // Send the bits to the miniport: ppdev->bPointerEnabled = pPointerAttributes->Enable; if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_POINTER_ATTR, ppdev->pPointerAttributes, ppdev->cjPointerAttributes, NULL, 0, &returnedDataLength)) { goto HideAndDecline; } return(SPS_ACCEPT_NOEXCLUDE); HideAndDecline: DrvMovePointer(pso, -1, -1, NULL); return(SPS_DECLINE); } /******************************Public*Routine******************************\ * VOID vDisablePointer * \**************************************************************************/ VOID vDisablePointer( PDEV* ppdev) { // Nothing to do, really } /******************************Public*Routine******************************\ * VOID vAssertModePointer * \**************************************************************************/ VOID vAssertModePointer( PDEV* ppdev, BOOL bEnable) { // Nothing to do, really } /******************************Public*Routine******************************\ * BOOL bEnablePointer * \**************************************************************************/ BOOL bEnablePointer( PDEV* ppdev) { return(TRUE); } /******************************Public*Routine******************************\ * BOOL bInitializePointer * * Initialize pointer during driver PDEV initialization -- early enough * so that we can affect what 'flGraphicsCaps' are passed back to GDI, * so that we can set GCAPS_ASYNCMOVE appropriately. * \**************************************************************************/ BOOL bInitializePointer( PDEV* ppdev) { VIDEO_POINTER_ATTRIBUTES* pPointerAttributes; LONG cjWidth; LONG cjMaxPointer; DWORD returnedDataLength; if (!EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES, NULL, 0, &ppdev->PointerCapabilities, sizeof(ppdev->PointerCapabilities), &returnedDataLength)) { if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER) { cjWidth = (ppdev->PointerCapabilities.MaxWidth + 7) / 8; cjMaxPointer = 2 * cjWidth * ppdev->PointerCapabilities.MaxHeight; ppdev->cjXorMaskStartOffset = cjMaxPointer / 2; ppdev->cjPointerAttributes = sizeof(VIDEO_POINTER_ATTRIBUTES) + cjMaxPointer; pPointerAttributes = (VIDEO_POINTER_ATTRIBUTES*) EngAllocMem(0, ppdev->cjPointerAttributes, ALLOC_TAG); if (pPointerAttributes != NULL) { ppdev->pPointerAttributes = pPointerAttributes; pPointerAttributes->WidthInBytes = cjWidth; pPointerAttributes->Width = ppdev->PointerCapabilities.MaxWidth; pPointerAttributes->Height = ppdev->PointerCapabilities.MaxHeight; } } } // We were successful even if the miniport doesn't support a // hardware pointer: return(TRUE); } /******************************Public*Routine******************************\ * VOID vUnitializePointer * * Undoes bInitializePointer. * \**************************************************************************/ VOID vUninitializePointer( PDEV* ppdev) { EngFreeMem(ppdev->pPointerAttributes); }