|
|
/******************************Module*Header*******************************\
* * ******************* * * GDI SAMPLE CODE * * ******************* * * Module Name: pointer.c * * This module contains the hardware pointer support for the display * driver. This supports both the built-in S3 hardware pointer and * some common DAC hardware pointers. * * Copyright (c) 1992-1998 Microsoft Corporation \**************************************************************************/
#include "precomp.h"
typedef struct BT485_POINTER_DATA {
LONG xHot; LONG yHot; ULONG ulExtendedDacControl; BYTE jCommandRegister0; BYTE jCommandRegister1; BYTE jCommandRegister2; BYTE jCommandRegister3;
} BT485_POINTER_DATA;
typedef struct TI025_POINTER_DATA {
ULONG ulExtendedDacControl;
} TI025_POINTER_DATA;
ULONG NewMmIoSetPointerShape( PDEV* ppdev, SURFOBJ* psoMsk, SURFOBJ* psoColor, XLATEOBJ* pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL* prcl, FLONG fl, BYTE* pBuf );
/******************************Public*Routine******************************\
* VOID vShowPointerBt485 * * Show or hide the Brooktree 485 hardware pointer. * \**************************************************************************/
VOID vShowPointerBt485( PDEV* ppdev, BT485_POINTER_DATA* pbp, BOOL bShow) { BYTE* pjIoBase = ppdev->pjIoBase;
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200);
OUTP(pjIoBase, BT485_ADDR_CMD_REG2, (bShow) ? (pbp->jCommandRegister2 | BT485_CURSOR_MODE2) : pbp->jCommandRegister2);
if (!bShow) { // Move the hardware pointer off-screen so that it doesn't flash
// in the old position when we finally turn it back on:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0300);
OUTP(pjIoBase, BT485_CURSOR_X_LOW, 0); OUTP(pjIoBase, BT485_CURSOR_X_HIGH, 0);
// A 'y' value of 1600 should be enough...
OUTP(pjIoBase, BT485_CURSOR_Y_LOW, 1663); OUTP(pjIoBase, BT485_CURSOR_Y_HIGH, (1663 >> 8)); }
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); }
/******************************Public*Routine******************************\
* VOID vMovePointerBt485 * * Move the Brooktree 485 hardware pointer. * \**************************************************************************/
VOID vMovePointerBt485( PDEV* ppdev, BT485_POINTER_DATA* pbp, LONG x, LONG y) { BYTE* pjIoBase = ppdev->pjIoBase;
x -= pbp->xHot; y -= pbp->yHot;
x += 64; y += 64;
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0300);
OUTP(pjIoBase, BT485_CURSOR_X_LOW, (x)); OUTP(pjIoBase, BT485_CURSOR_X_HIGH, (x >> 8));
OUTP(pjIoBase, BT485_CURSOR_Y_LOW, (y)); OUTP(pjIoBase, BT485_CURSOR_Y_HIGH, (y >> 8));
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); }
/******************************Public*Routine******************************\
* BOOL bSetPointerShapeBt485 * * Set the Brooktree 485 hardware pointer shape. * \**************************************************************************/
BOOL bSetPointerShapeBt485( PDEV* ppdev, BT485_POINTER_DATA* pbp, LONG x, // If -1, pointer should be created hidden
LONG y, LONG xHot, LONG yHot, LONG cx, LONG cy, BYTE* pjShape) { BYTE* pjIoBase = ppdev->pjIoBase; BYTE* pjSrc; LONG i;
// Get access to command register 3:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0100); OUTP(pjIoBase, BT485_ADDR_CMD_REG0, pbp->jCommandRegister0 | BT485_CMD_REG_3_ACCESS);
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); OUTP(pjIoBase, BT485_ADDR_CMD_REG1, 0x01);
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200); OUTP(pjIoBase, BT485_ADDR_CMD_REG3, pbp->jCommandRegister3);
// Disable the pointer:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200); OUTP(pjIoBase, BT485_ADDR_CMD_REG2, pbp->jCommandRegister2);
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); OUTP(pjIoBase, BT485_ADDR_CUR_RAM_WRITE, 0x0);
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200);
// Point to first XOR word:
pjSrc = pjShape + 2;
// Download the XOR mask:
for (i = 256; i > 0; i--) { OUTP(pjIoBase, BT485_CUR_RAM_ARRAY_DATA, *(pjSrc)); OUTP(pjIoBase, BT485_CUR_RAM_ARRAY_DATA, *(pjSrc + 1));
// Skip over AND word:
pjSrc += 4; }
// Pointer to first AND word:
pjSrc = pjShape;
// Download the AND mask:
for (i = 256; i > 0; i--) { OUTP(pjIoBase, BT485_CUR_RAM_ARRAY_DATA, *(pjSrc)); OUTP(pjIoBase, BT485_CUR_RAM_ARRAY_DATA, *(pjSrc + 1));
// Skip over XOR word:
pjSrc += 4; }
pbp->xHot = xHot; pbp->yHot = yHot;
// Set the position of the pointer:
if (x != -1) { x -= xHot; y -= yHot;
x += 64; y += 64;
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0300);
OUTP(pjIoBase, BT485_CURSOR_X_LOW, (x)); OUTP(pjIoBase, BT485_CURSOR_X_HIGH, (x >> 8));
OUTP(pjIoBase, BT485_CURSOR_Y_LOW, (y)); OUTP(pjIoBase, BT485_CURSOR_Y_HIGH, (y >> 8));
// Enable the pointer:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200); OUTP(pjIoBase, BT485_ADDR_CMD_REG2, pbp->jCommandRegister2 | BT485_CURSOR_MODE2); } else { // Move the hardware pointer off-screen so that it doesn't flash
// in the old position when we finally turn it back on:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0300);
OUTP(pjIoBase, BT485_CURSOR_X_LOW, 0); OUTP(pjIoBase, BT485_CURSOR_X_HIGH, 0);
// A 'y' value of 1600 should be enough...
OUTP(pjIoBase, BT485_CURSOR_Y_LOW, 1663); OUTP(pjIoBase, BT485_CURSOR_Y_HIGH, (1663 >> 8)); }
// Reset the DAC extended register:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl);
return(TRUE); }
/******************************Public*Routine******************************\
* VOID vEnablePointerBt485 * * Get the hardware ready to use the Brooktree 485 hardware pointer. * \**************************************************************************/
VOID vEnablePointerBt485( PDEV* ppdev, BT485_POINTER_DATA* pbp, BOOL bFirst) { BYTE* pjIoBase = ppdev->pjIoBase;
if (bFirst) { // Make a copy of the extended DAC control register:
OUTP(pjIoBase, CRTC_INDEX, EX_DAC_CT);
pbp->ulExtendedDacControl = ((INP(pjIoBase, CRTC_DATA) << 8) | EX_DAC_CT) & ~0x0300;
// Make copies of command registers 1 and 2:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0100); pbp->jCommandRegister0 = INP(pjIoBase, BT485_ADDR_CMD_REG0);
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200); pbp->jCommandRegister1 = INP(pjIoBase, BT485_ADDR_CMD_REG1);
// Make a copy of command register 2 and mask off the pointer control bits:
pbp->jCommandRegister2 = INP(pjIoBase, BT485_ADDR_CMD_REG2) & BT485_CURSOR_DISABLE;
// Disable the pointer:
OUTP(pjIoBase, BT485_ADDR_CMD_REG2, pbp->jCommandRegister2);
// To access command register 3, we do the following:
// 1. Set the command register access bit in command register 0.
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0100); OUTP(pjIoBase, BT485_ADDR_CMD_REG0, pbp->jCommandRegister0 | BT485_CMD_REG_3_ACCESS);
// 2. Set the index to 1.
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); OUTP(pjIoBase, BT485_ADDR_CMD_REG1, 0x01);
// 3. Now read command register 3.
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0200); pbp->jCommandRegister3 = INP(pjIoBase, BT485_ADDR_CMD_REG3);
// Set command register 3 for a 64 X 64 pointer:
pbp->jCommandRegister3 |= BT485_64X64_CURSOR; OUTP(pjIoBase, BT485_ADDR_CMD_REG3, pbp->jCommandRegister3);
// Disable access to command register 3:
OUTPW(pjIoBase, CRTC_INDEX, (pbp->ulExtendedDacControl | 0x0100)); OUTP(pjIoBase, BT485_ADDR_CMD_REG0, pbp->jCommandRegister0);
// Set the colour 1 and colour 2 for the pointer. Select address
// register; pointer/overscan color write on the Bt485.
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl | 0x0100); OUTP(pjIoBase, BT485_ADDR_CUR_COLOR_WRITE, BT485_CURSOR_COLOR_1);
// Output the RGB for pointer colour 1 (black):
OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0x00); OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0x00); OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0x00);
// Output the RGB for pointer colour 2 (white):
OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0xff); OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0xff); OUTP(pjIoBase, BT485_CUR_COLOR_DATA, 0xff);
// Reset the DAC control register:
OUTPW(pjIoBase, CRTC_INDEX, pbp->ulExtendedDacControl); } }
/******************************Public*Routine******************************\
* VOID vShowPointerTi025 * * Show or hide the TI 025 hardware pointer. * \**************************************************************************/
VOID vShowPointerTi025( PDEV* ppdev, TI025_POINTER_DATA* ptp, BOOL bShow) { BYTE* pjIoBase = ppdev->pjIoBase; BYTE jDacControl;
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl | 0x0100);
OUTP(pjIoBase, 0x3c6, 6);
jDacControl = INP(pjIoBase, 0x3c7);
if (bShow) jDacControl |= 0x40; else { jDacControl &= ~0x40;
// Move the hardware pointer off-screen so that it doesn't flash
// in the old position when we finally turn it back on:
OUTP(pjIoBase, 0x3c6, 0); OUTP(pjIoBase, 0x3c7, 0);
OUTP(pjIoBase, 0x3c6, 1); OUTP(pjIoBase, 0x3c7, 0);
OUTP(pjIoBase, 0x3c6, 2); OUTP(pjIoBase, 0x3c7, 1663); // A 'y' value of 1600 should be enough...
OUTP(pjIoBase, 0x3c6, 3); OUTP(pjIoBase, 0x3c7, (1663 >> 8)); }
OUTP(pjIoBase, 0x3c6, 6); OUTP(pjIoBase, 0x3c7, jDacControl);
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl); }
/******************************Public*Routine******************************\
* VOID vMovePointerTi025 * * Move the TI 025 hardware pointer. * \**************************************************************************/
VOID vMovePointerTi025( PDEV* ppdev, TI025_POINTER_DATA* ptp, LONG x, LONG y) { BYTE* pjIoBase = ppdev->pjIoBase;
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl | 0x0100);
OUTP(pjIoBase, 0x3c6, 0); OUTP(pjIoBase, 0x3c7, (x));
OUTP(pjIoBase, 0x3c6, 1); OUTP(pjIoBase, 0x3c7, (x >> 8));
OUTP(pjIoBase, 0x3c6, 2); OUTP(pjIoBase, 0x3c7, (y));
OUTP(pjIoBase, 0x3c6, 3); OUTP(pjIoBase, 0x3c7, (y >> 8));
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl); }
/******************************Public*Routine******************************\
* BOOL bSetPointerShapeTi025 * * Set the TI 025 hardware pointer shape. * * Don't do word outs to the DAC because they may not be performed correctly * on some ISA machines. * \**************************************************************************/
BOOL bSetPointerShapeTi025( PDEV* ppdev, TI025_POINTER_DATA* ptp, LONG x, // If -1, pointer should be created hidden
LONG y, LONG xHot, LONG yHot, LONG cx, LONG cy, BYTE* pjShape) { BYTE* pjIoBase = ppdev->pjIoBase; LONG i; DWORD dwShape; LONG cShift; WORD wMask; WORD wAnd; WORD wXor; BYTE jDacControl;
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl | 0x0100);
// Hide the pointer, otherwise it will show random garbage when
// animating cursors on the TI 020 DAC.
OUTP(pjIoBase, 0x3c6, 6);
jDacControl = INP(pjIoBase, 0x3c7);
jDacControl &= ~0x40;
OUTP(pjIoBase, 0x3c7, jDacControl);
// Set the pointer hot-spot offset:
OUTP(pjIoBase, 0x3c6, 4); OUTP(pjIoBase, 0x3c7, xHot); OUTP(pjIoBase, 0x3c6, 5); OUTP(pjIoBase, 0x3c7, yHot);
// Download the pointer shape. Do the OUTs for downloading the
// pointer data slowly -- don't use REP OUTSB.
OUTP(pjIoBase, 0x3c6, 8); OUTP(pjIoBase, 0x3c7, 0); OUTP(pjIoBase, 0x3c6, 9); OUTP(pjIoBase, 0x3c7, 0); // Start with pixel 0 of the pointer
OUTP(pjIoBase, 0x3c6, 10); // Get ready for downloading
for (i = 256; i != 0; i--) { // Every time through this loop we'll handle one AND word and one
// XOR word of the pointer data (which is good because the S3
// display driver gives us the pointer shape in 'pjShape' such that
// it starts with the first AND word, followed by the first XOR
// word, followed by the second AND word, etc.)
dwShape = 0;
// The AND word is first. Don't forget about endianness...
wAnd = (*(pjShape) << 8) | *(pjShape + 1); for (wMask = 0x8000, cShift = 16; wMask != 0; wMask >>= 1, cShift--) { dwShape |= ((wAnd & wMask) << cShift); }
// The XOR word is next. Don't forget about endianness...
wXor = (*(pjShape + 2) << 8) | *(pjShape + 3); for (wMask = 0x8000, cShift = 15; wMask != 0; wMask >>= 1, cShift--) { dwShape |= ((wXor & wMask) << cShift); }
// We've now interleaved the AND and XOR words into a dword such
// that if the AND word bits are ABC... and the XOR word bits are
// 123..., the resulting dword will be A1B2C3...
OUTP(pjIoBase, 0x3c7, (dwShape >> 24)); OUTP(pjIoBase, 0x3c7, (dwShape >> 16)); OUTP(pjIoBase, 0x3c7, (dwShape >> 8)); OUTP(pjIoBase, 0x3c7, (dwShape));
// Advance to next AND/XOR word pair:
pjShape += 4; }
if (x != -1) { // Set the position of the pointer:
OUTP(pjIoBase, 0x3c6, 0); OUTP(pjIoBase, 0x3c7, (x));
OUTP(pjIoBase, 0x3c6, 1); OUTP(pjIoBase, 0x3c7, (x >> 8));
OUTP(pjIoBase, 0x3c6, 2); OUTP(pjIoBase, 0x3c7, (y));
OUTP(pjIoBase, 0x3c6, 3); OUTP(pjIoBase, 0x3c7, (y >> 8));
// Show the pointer:
OUTP(pjIoBase, 0x3c6, 6);
OUTP(pjIoBase, 0x3c7, jDacControl | 0x40); } else { // Move the hardware pointer off-screen so that it doesn't flash
// in the old position when we finally turn it back on:
OUTP(pjIoBase, 0x3c6, 0); OUTP(pjIoBase, 0x3c7, 0);
OUTP(pjIoBase, 0x3c6, 1); OUTP(pjIoBase, 0x3c7, 0);
OUTP(pjIoBase, 0x3c6, 2); OUTP(pjIoBase, 0x3c7, 1663); // A 'y' value of 1600 should be enough...
OUTP(pjIoBase, 0x3c6, 3); OUTP(pjIoBase, 0x3c7, (1663 >> 8)); }
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl);
// Reset DAC read mask to 0xff:
OUTP(pjIoBase, 0x3c6, 0xff);
return(TRUE); }
/******************************Public*Routine******************************\
* VOID vEnablePointerTi025 * * Get the hardware ready to use the TI 025 hardware pointer. * * Don't do word outs to the DAC because they may not be performed correctly * on some ISA machines. * \**************************************************************************/
VOID vEnablePointerTi025( PDEV* ppdev, TI025_POINTER_DATA* ptp, BOOL bFirst) { BYTE* pjIoBase = ppdev->pjIoBase; BYTE jMode; BYTE jDacControl;
// Make a copy of the extended DAC control register:
OUTP(pjIoBase, CRTC_INDEX, EX_DAC_CT);
ptp->ulExtendedDacControl = ((INP(pjIoBase, CRTC_DATA) << 8) | EX_DAC_CT) & ~0x0300;
// Disable the DAC's Bt485 emulation so that we can use the TI hardware
// pointer.
OUTP(pjIoBase, CRTC_INDEX, 0x5C);
jMode = INP(pjIoBase, CRTC_DATA);
OUTP(pjIoBase, CRTC_DATA, jMode & ~0x20); // Select TI mode in the DAC
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl | 0x0100);
OUTP(pjIoBase, 0x3c6, 6);
jDacControl = INP(pjIoBase, 0x3c7);
OUTP(pjIoBase, 0x3c7, jDacControl & 0x7f); // Set to TI mode (non planar)
// Set the pointer colours to black and white.
OUTP(pjIoBase, 0x3c6, 0x26); OUTP(pjIoBase, 0x3c7, 0xff); // Foreground red component
OUTP(pjIoBase, 0x3c6, 0x27); OUTP(pjIoBase, 0x3c7, 0xff); // Foreground green component
OUTP(pjIoBase, 0x3c6, 0x28); OUTP(pjIoBase, 0x3c7, 0xff); // Foreground blue component
OUTP(pjIoBase, 0x3c6, 0x23); OUTP(pjIoBase, 0x3c7, 0x00); // Background red component
OUTP(pjIoBase, 0x3c6, 0x24); OUTP(pjIoBase, 0x3c7, 0x00); // Background green component
OUTP(pjIoBase, 0x3c6, 0x25); OUTP(pjIoBase, 0x3c7, 0x00); // Background blue component
OUTPW(pjIoBase, CRTC_INDEX, ptp->ulExtendedDacControl);
OUTP(pjIoBase, 0x3c6, 0xff); // Reset DAC read mask to 0xff
// Note that we don't have to bother hiding the pointer, because
// vShowPointer will be called immediately...
}
/******************************Public*Routine******************************\
* VOID vShowPointerS3 * * Show or hide the S3 hardware pointer. * * We hide the pointer by making it only one row high (we always reserve * the bottom scan of the pointer shape to be invisible). We do it this * way because we ran into problems doing it with any other method: * * 1. Disabling the hardware pointer via register CR45 will hang * 80x/928/864 chips if it is done at exactly the wrong time during * the horizontal retrace. It's is not safe to wait for vertical * blank and do it then, because we're a user mode process and * could get context switched after doing the wait but before setting * the bit. * * 2. Simply changing the pointer position to move it off-screen works, * but is not a good solution because the pointer position is latched * by the hardware, and it usually takes a couple of frames for the * new position to take effect (which causes the pointer to jump even * more than it currently does). * * 3. Using registers CR4C and CR4D to switch to a pre-defined 'invisible' * pointer also worked, but still caused machines to crash with the * same symptoms as from solution 1 (although it was somewhat more * rare). * \**************************************************************************/
VOID vShowPointerS3( PDEV* ppdev, BOOL bShow) // If TRUE, show the pointer. If FALSE, hide the pointer.
{ BYTE* pjIoBase = ppdev->pjIoBase; LONG x; LONG y; LONG dx; LONG dy;
// If we don't wait for vertical retrace here, the S3 sometimes ignores
// the setting of the new pointer position:
while (INP(pjIoBase, STATUS_1) & VBLANK_ACTIVE) ; // Wait for bit 3 to become 0
while (!(INP(pjIoBase, STATUS_1) & VBLANK_ACTIVE)) ; // Wait for bit 3 to become 1
if (bShow) { // Make the hardware pointer visible:
x = ppdev->xPointer; y = ppdev->yPointer; dx = ppdev->dxPointer; dy = ppdev->dyPointer; } else { // Move the hardware pointer off-screen so that it doesn't flash
// in the old position when we finally turn it back on:
x = ppdev->cxScreen + 64; y = ppdev->cyScreen + 64; dx = 0; dy = HW_POINTER_HIDE; }
// Note that due to register shadowing, these OUTs should be done
// in a specific order, otherwise you may get a flashing pointer:
OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGX_MSB | ((x >> 8) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGX_LSB | ((x & 0xff) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGY_LSB | ((y & 0xff) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_DX | ((dx) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_DY | ((dy) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGY_MSB | ((y >> 8) << 8)); }
/******************************Public*Routine******************************\
* VOID vMovePointerS3 * * Move the S3 hardware pointer. * \**************************************************************************/
VOID vMovePointerS3( PDEV* ppdev, LONG x, LONG y) { BYTE* pjIoBase = ppdev->pjIoBase; LONG dx; LONG dy;
// 'dx' and 'dy' are the offsets into the pointer bitmap at which
// the hardware is supposed to start drawing, when the pointer is
// along the left or top edge and needs to be clipped:
x -= ppdev->xPointerHot; y -= ppdev->yPointerHot;
dx = 0; dy = 0;
if (x <= 0) { dx = -x; x = 0; }
if (y <= 0) { dy = -y; y = 0; }
// Account for pointer position scaling in high-colour modes:
x <<= ppdev->cPointerShift;
ppdev->dxPointer = dx; ppdev->dyPointer = dy; ppdev->xPointer = x; ppdev->yPointer = y;
// Note that due to register shadowing, these OUTs should be done
// in a specific order, otherwise you may get a flashing pointer:
OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGX_MSB | ((x >> 8) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGX_LSB | ((x & 0xff) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGY_LSB | ((y & 0xff) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_DX | ((dx) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_DY | ((dy) << 8)); OUTPW(pjIoBase, CRTC_INDEX, HGC_ORGY_MSB | ((y >> 8) << 8)); }
/******************************Public*Routine******************************\
* VOID vSetPointerShapeS3 * \**************************************************************************/
VOID vSetPointerShapeS3( SURFOBJ* pso, LONG x, // Relative coordinates
LONG y, // Relative coordinates
LONG xHot, LONG yHot, BYTE* pjShape, FLONG fl) { BYTE* pjIoBase; PDEV* ppdev; ULONG* pulSrc; ULONG* pulDst; LONG i;
ppdev = (PDEV*) pso->dhpdev; pjIoBase = ppdev->pjIoBase;
// 1. Hide the current pointer.
if (!(fl & SPS_ANIMATEUPDATE)) { // Hide the pointer to try and lessen the jumpiness when the
// new shape has a different hot spot. We don't hide the
// pointer while animating, because that definitely causes
// flashing:
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev); OUTPW(pjIoBase, CRTC_INDEX, HGC_DY | (HW_POINTER_HIDE << 8)); RELEASE_CRTC_CRITICAL_SECTION(ppdev); }
// 2. Wait until the vertical retrace is done.
// --
//
// If we don't wait for vertical retrace here, the S3 sometimes ignores
// the setting of the new pointer position:
while (INP(pjIoBase, STATUS_1) & VBLANK_ACTIVE) ; // Wait for bit 3 to become 0
while (!(INP(pjIoBase, STATUS_1) & VBLANK_ACTIVE)) ; // Wait for bit 3 to become 1
// 3. Set the new pointer position.
// --
ppdev->xPointerHot = xHot; ppdev->yPointerHot = yHot;
DrvMovePointer(pso, x, y, NULL); // Note: Must pass relative coordinates!
// 4. Download the new pointer shape.
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
ppdev->pfnBankSelectMode(ppdev, ppdev->pvBankData, BANK_ON); ppdev->pfnBankMap(ppdev, ppdev->pvBankData, ppdev->iPointerBank);
pulSrc = (ULONG*) pjShape; pulDst = (ULONG*) ppdev->pvPointerShape;
if (DIRECT_ACCESS(ppdev)) { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { *pulDst++ = *pulSrc++; } } else { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { WRITE_REGISTER_ULONG(pulDst, *pulSrc); pulSrc++; pulDst++; } }
ppdev->pfnBankSelectMode(ppdev, ppdev->pvBankData, BANK_OFF);
RELEASE_CRTC_CRITICAL_SECTION(ppdev); }
/******************************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) { PDEV* ppdev;
ppdev = (PDEV*) pso->dhpdev;
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
if (x != -1) { if (ppdev->flCaps & CAPS_DAC_POINTER) { ppdev->pfnMovePointer(ppdev, ppdev->pvPointerData, x, y); } else { vMovePointerS3(ppdev, x, y); }
if (!ppdev->bHwPointerActive) { // We have to make the pointer visible:
ppdev->bHwPointerActive = TRUE;
if (ppdev->flCaps & CAPS_DAC_POINTER) { ppdev->pfnShowPointer(ppdev, ppdev->pvPointerData, TRUE); } else { vShowPointerS3(ppdev, TRUE); } } } else { if (ppdev->bHwPointerActive) { // The pointer is visible, and we've been asked to hide it:
ppdev->bHwPointerActive = FALSE;
if (ppdev->flCaps & CAPS_DAC_POINTER) { ppdev->pfnShowPointer(ppdev, ppdev->pvPointerData, FALSE); } else { vShowPointerS3(ppdev, FALSE); } } }
RELEASE_CRTC_CRITICAL_SECTION(ppdev);
// Note that we don't have to modify 'prcl', since we have a
// NOEXCLUDE pointer...
}
/******************************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) { PDEV* ppdev; DWORD* pul; ULONG cx; ULONG cy; LONG i; LONG j; BYTE* pjSrcScan; BYTE* pjDstScan; LONG lSrcDelta; LONG lDstDelta; WORD* pwSrc; WORD* pwDst; LONG cwWhole; BOOL bAccept; BYTE ajBuf[HW_POINTER_TOTAL_SIZE];
ppdev = (PDEV*) pso->dhpdev;
// When CAPS_SW_POINTER is set, we have no hardware pointer available,
// so we always ask GDI to simulate the pointer for us, using
// DrvCopyBits calls:
if (ppdev->flCaps & CAPS_SW_POINTER) return(SPS_DECLINE);
// We're not going to handle any colour pointers, pointers that
// are larger than our hardware allows, or flags that we don't
// understand.
//
// (Note that the spec says we should decline any flags we don't
// understand, but we'll actually be declining if we don't see
// the only flag we *do* understand...)
//
// Our old documentation says that 'psoMsk' may be NULL, which means
// that the pointer is transparent. Well, trust me, that's wrong.
// I've checked GDI's code, and it will never pass us a NULL psoMsk:
cx = psoMsk->sizlBitmap.cx; // Note that 'sizlBitmap.cy' accounts
cy = psoMsk->sizlBitmap.cy >> 1; // for the double height due to the
// inclusion of both the AND masks
// and the XOR masks. For now, we're
// only interested in the true
// pointer dimensions, so we divide
// by 2.
// We reserve the bottom scan of the pointer shape and keep it
// empty so that we can hide the pointer by changing the S3's
// display start y-pixel position register to show only the bottom
// scan of the pointer shape:
if ((cx > HW_POINTER_DIMENSION) || (cy > (HW_POINTER_DIMENSION - 1)) || (psoColor != NULL) || !(fl & SPS_CHANGE) || (cx & 0x7)) // make sure cx is a multiple of 8 (byte aligned).
{ goto HideAndDecline; }
ASSERTDD(psoMsk != NULL, "GDI gave us a NULL psoMsk. It can't do that!"); //ASSERTDD(pso->iType == STYPE_DEVICE, "GDI gave us a weird surface");
if ((cx <= (HW_POINTER_DIMENSION / 2)) && !(ppdev->flCaps & CAPS_DAC_POINTER) && (ppdev->flCaps & CAPS_NEW_MMIO)) { return( NewMmIoSetPointerShape( ppdev, psoMsk, psoColor, pxlo, xHot, yHot, x, y, prcl, fl, ajBuf )); }
pul = (ULONG*) &ajBuf[0]; for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { // Here we initialize the entire pointer work buffer to be
// transparent (the S3 has no means of specifying a pointer size
// other than 64 x 64 -- so if we're asked to draw a 32 x 32
// pointer, we want the unused portion to be transparent).
//
// The S3's hardware pointer is defined by an interleaved pattern
// of AND words and XOR words. So a totally transparent pointer
// starts off with the word 0xffff, followed by the word 0x0000,
// followed by 0xffff, etc.. Since we're a little endian system,
// this is simply the repeating dword '0x0000ffff'.
//
// The compiler is nice enough to optimize this into a REP STOSD
// for us:
*pul++ = 0x0000ffff; }
// Now we're going to take the requested pointer AND masks and XOR
// masks and combine them into our work buffer, being careful of
// the edges so that we don't disturb the transparency when the
// requested pointer size is not a multiple of 16.
//
// 'psoMsk' is actually cy * 2 scans high; the first 'cy' scans
// define the AND mask. So we start with that:
pjSrcScan = psoMsk->pvScan0; lSrcDelta = psoMsk->lDelta; pjDstScan = &ajBuf[0]; // Start with first AND word
lDstDelta = HW_POINTER_DIMENSION / 4;// Every 8 pels is one AND/XOR word
cwWhole = cx / 16; // Each word accounts for 16 pels
for (i = cy; i != 0; i--) { pwSrc = (WORD*) pjSrcScan; pwDst = (WORD*) pjDstScan;
for (j = cwWhole; j != 0; j--) { *pwDst = *pwSrc; pwSrc += 1; // Go to next word in source mask
pwDst += 2; // Skip over the XOR word in the dest mask
}
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; }
// Now handle the XOR mask:
pjDstScan = &ajBuf[2]; // Start with first XOR word
for (i = cy; i != 0; i--) { pwSrc = (WORD*) pjSrcScan; pwDst = (WORD*) pjDstScan;
for (j = cwWhole; j != 0; j--) { *pwDst = *pwSrc; pwSrc += 1; // Go to next word in source mask
pwDst += 2; // Skip over the AND word in the dest mask
}
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; }
// Okay, I admit it -- I'm wildly inconsistent here. I pass
// absolute (x, y) coordinates to pfnSetPointerShape, but pass
// relative (x, y) coordinates to vSetPointerShapeS3. I would
// clean this all up, but we're too close to shipping. LATER!
if (ppdev->flCaps & CAPS_DAC_POINTER) { ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
bAccept = ppdev->pfnSetPointerShape(ppdev, ppdev->pvPointerData, x, y, xHot, yHot, cx, cy, &ajBuf[0]);
RELEASE_CRTC_CRITICAL_SECTION(ppdev);
ppdev->bHwPointerActive = (x != -1);
if (!bAccept) goto HideAndDecline; } else { vSetPointerShapeS3(pso, x, y, xHot, yHot, &ajBuf[0], fl); }
// Since it's a hardware pointer, GDI doesn't have to worry about
// overwriting the pointer on drawing operations (meaning that it
// doesn't have to exclude the pointer), so we return 'NOEXCLUDE'.
// Since we're returning 'NOEXCLUDE', we also don't have to update
// the 'prcl' that GDI passed us.
return(SPS_ACCEPT_NOEXCLUDE);
HideAndDecline:
// Since we're declining the new pointer, GDI will simulate it via
// DrvCopyBits calls. So we should really hide the old hardware
// pointer if it's visible. We can get DrvMovePointer to do this
// for us:
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) { ULONG* pulDst; LONG i; LONG lPointerShape;
// We will turn any hardware pointer -- either in the S3 or in the
// DAC -- off to begin with:
ppdev->bHwPointerActive = FALSE;
if (ppdev->flCaps & CAPS_SW_POINTER) { // With a software pointer, we don't have to do anything.
} else if (ppdev->flCaps & CAPS_DAC_POINTER) { // Hide the DAC pointer:
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
// hide the pointer by moving offscreen
ppdev->pfnShowPointer(ppdev, ppdev->pvPointerData, FALSE);
// but enable the pointer registers
ppdev->pfnEnablePointer(ppdev, ppdev->pvPointerData, TRUE);
RELEASE_CRTC_CRITICAL_SECTION(ppdev); } else { // We're using the built-in hardware pointer:
if (bEnable) { ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
ppdev->cPointerShift = 0;
if (ppdev->iBitmapFormat > BMF_8BPP) { // Initializing the pointer colours is a bit different
// for high-colour modes:
if (ppdev->flCaps & CAPS_SCALE_POINTER) { ppdev->cPointerShift = 1; ppdev->ulHwGraphicsCursorModeRegister_45 |= (0x4 << 8); } }
// We download an invisible pointer shape because we're about
// to enable the hardware pointer, but we still want the
// pointer hidden until we get the first DrvSetPointerShape
// call:
ppdev->pfnBankSelectMode(ppdev, ppdev->pvBankData, BANK_ON);
ppdev->pfnBankMap(ppdev, ppdev->pvBankData, ppdev->iPointerBank);
pulDst = (ULONG*) ppdev->pvPointerShape;
if (DIRECT_ACCESS(ppdev)) { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { *pulDst++ = 0x0000ffff; } } else { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { WRITE_REGISTER_ULONG(pulDst, 0x0000ffff); pulDst++; } }
ppdev->pfnBankSelectMode(ppdev, ppdev->pvBankData, BANK_OFF);
// Point the S3 to where we're storing the pointer shape.
// The location is specified as a multiple of 1024:
lPointerShape = ppdev->cjPointerOffset / 1024;
OUTPW(ppdev->pjIoBase, CRTC_INDEX, CR4C | ((lPointerShape >> 8) << 8)); OUTPW(ppdev->pjIoBase, CRTC_INDEX, CR4D | ((lPointerShape & 0xff) << 8));
// Now hide it by moving it off-screen:
vShowPointerS3(ppdev, FALSE);
// Enable the hardware pointer. As per the 8/31/93 Design
// Alert from S3 Incorporated, there's a goofy bug in all
// S3 chips up to the 928 where writing to this register
// at the same time as a horizontal sync may cause the
// chip to crash. So we wait for the vertical sync to be safe.
//
// Note that since we're a preemptive multitasking
// operating system, the following code is not guaranteed
// to be safe. To do that, we would have to put this in
// the miniport, where we could disable all interrupts while
// we wait for the vertical sync.
//
// However, this is only ever executed once at initialization
// and every time full-screen is executed, so I would expect
// the chances of there still being a problem to be extremely
// small:
while (INP(ppdev->pjIoBase, STATUS_1) & VBLANK_ACTIVE) ; // Wait for bit 3 to become 0
while (!(INP(ppdev->pjIoBase, STATUS_1) & VBLANK_ACTIVE)) ; // Wait for bit 3 to become 1
OUTPW(ppdev->pjIoBase, CRTC_INDEX, ppdev->ulHwGraphicsCursorModeRegister_45 | (HGC_ENABLE << 8));
RELEASE_CRTC_CRITICAL_SECTION(ppdev); } } }
/******************************Public*Routine******************************\
* BOOL bEnablePointer * \**************************************************************************/
BOOL bEnablePointer( PDEV* ppdev) { RECTL rclDraw; RECTL rclBank; LONG iBank; LONG cjOffset; LONG cjOffsetInBank;
if (ppdev->flCaps & CAPS_SW_POINTER) { // With a software pointer, we don't have to do anything.
} else if (ppdev->flCaps & CAPS_DAC_POINTER) { // Initialize the DAC pointer:
if (ppdev->flCaps & CAPS_BT485_POINTER) { ppdev->pfnShowPointer = vShowPointerBt485; ppdev->pfnMovePointer = vMovePointerBt485; ppdev->pfnSetPointerShape = bSetPointerShapeBt485; ppdev->pfnEnablePointer = vEnablePointerBt485; } else { ASSERTDD(ppdev->flCaps & CAPS_TI025_POINTER, "A new DAC type was added?");
ppdev->pfnShowPointer = vShowPointerTi025; ppdev->pfnMovePointer = vMovePointerTi025; ppdev->pfnSetPointerShape = bSetPointerShapeTi025; ppdev->pfnEnablePointer = vEnablePointerTi025; }
ppdev->pvPointerData = &ppdev->ajPointerData[0];
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
ppdev->pfnEnablePointer(ppdev, ppdev->pvPointerData, TRUE);
RELEASE_CRTC_CRITICAL_SECTION(ppdev); } else { // Enable the S3 hardware pointer.
// We're going to assume that the pointer shape doesn't span
// more than one bank. We have to figure out what bank that
// will be, and so we call 'pfnBankCompute' with the start
// point:
rclDraw.left = rclDraw.right = ppdev->xPointerShape; rclDraw.top = rclDraw.bottom = ppdev->yPointerShape;
ppdev->pfnBankCompute(ppdev, &rclDraw, &rclBank, &cjOffset, &iBank);
cjOffsetInBank = ppdev->cjPointerOffset - cjOffset;
ASSERTDD(cjOffsetInBank + HW_POINTER_TOTAL_SIZE <= ppdev->cjBank, "SetPointerShape assumes pointer shape doesn't span banks");
// When bank 'iPointerBank' is mapped in, 'pvPointerShape' is the
// actual pointer to be the beginning of the pointer shape bits
// in off-screen memory:
ppdev->pvPointerShape = ppdev->pjScreen + cjOffsetInBank; ppdev->iPointerBank = iBank;
// Get a copy of the current register '45' state, so that whenever
// we enable or disable the S3 hardware pointer, we don't have to
// do a read-modify-write on this register:
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
OUTP(ppdev->pjIoBase, CRTC_INDEX, HGC_MODE); ppdev->ulHwGraphicsCursorModeRegister_45 = ((INP(ppdev->pjIoBase, CRTC_DATA) << 8) | HGC_MODE) & ~(HGC_ENABLE << 8);
RELEASE_CRTC_CRITICAL_SECTION(ppdev); }
// Actually turn on the pointer:
vAssertModePointer(ppdev, TRUE);
DISPDBG((5, "Passed bEnablePointer"));
return(TRUE); }
/******************************Public*Routine******************************\
* * Sets the new pointer shape. * \**************************************************************************/
ULONG NewMmIoSetPointerShape( PDEV* ppdev, SURFOBJ* psoMsk, SURFOBJ* psoColor, XLATEOBJ* pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL* prcl, FLONG fl, BYTE* pBuf) { ULONG cx; ULONG cy; LONG i; LONG j; BYTE* pjSrcScan; BYTE* pjDstScan; LONG lSrcDelta; LONG lDstDelta; WORD* pwSrc; WORD* pwDst; BYTE* pbSrc; BYTE* pbDst;
ULONG* pulDst; ULONG* pulSrc;
LONG cxWhole; LONG xHotWordBnd;
ULONG ulTransp = 0xFFFF0000L; ULONG ulData, ulPreviousData;
UCHAR ucTemp;
// We're not going to handle any colour pointers, pointers that
// are larger than our hardware allows, or flags that we don't
// understand.
//
// (Note that the spec says we should decline any flags we don't
// understand, but we'll actually be declining if we don't see
// the only flag we *do* understand...)
//
// Our old documentation says that 'psoMsk' may be NULL, which means
// that the pointer is transparent. Well, trust me, that's wrong.
// I've checked GDI's code, and it will never pass us a NULL psoMsk:
cx = psoMsk->sizlBitmap.cx; // Note that 'sizlBitmap.cy' accounts
cy = psoMsk->sizlBitmap.cy >> 1; // for the double height due to the
// inclusion of both the AND masks
// and the XOR masks. For now, we're
// only interested in the true
// pointer dimensions, so we divide
// by 2.
//
// 'psoMsk' is actually cy * 2 scans high; the first 'cy' scans
// define the AND mask. So we start with that:
pjSrcScan = psoMsk->pvScan0; lSrcDelta = psoMsk->lDelta; lDstDelta = HW_POINTER_DIMENSION / 4; // Every 8 pels is one AND/XOR word
cxWhole = cx / 16; // Each word accounts for 16 pels
// caculating pointer checksum whether update the pointer or not
pulSrc = (ULONG*) pjSrcScan; ulData = 0L;
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
if (!(fl & SPS_ANIMATEUPDATE)) { OUTPW(ppdev->pjIoBase, CRTC_INDEX, HGC_DY | (HW_POINTER_HIDE << 8)); }
if(x >= 0) { vMovePointerS3(ppdev, x, y); }
RELEASE_CRTC_CRITICAL_SECTION(ppdev);
// Now we're going to take the requested pointer AND masks and XOR
// masks and combine them into our work buffer, being careful of
// the edges so that we don't disturb the transparency when the
// requested pointer size is not a multiple of 16.
pulDst = (ULONG*) pBuf;
for (i = 0; i < HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i++) { // Here we initialize the entire pointer work buffer to be
// transparent (the S3 has no means of specifying a pointer size
// other than 64 x 64 -- so if we're asked to draw a 32 x 32
// pointer, we want the unused portion to be transparent).
//
// The S3's hardware pointer is defined by an interleaved pattern
// of AND words and XOR words. So a totally transparent pointer
// starts off with the word 0xffff, followed by the word 0x0000,
// followed by 0xffff, etc.. Since we're a little endian system,
// this is simply the repeating dword '0x0000ffff'.
//
// The compiler is nice enough to optimize this into a REP STOSD
// for us:
*pulDst++ = 0x0000ffff; }
// ekl - take care word bnd.
// Start with first AND word
pjDstScan = (BYTE *) pBuf;
pjDstScan += ((HW_POINTER_DIMENSION / 2 - yHot) * lDstDelta + (HW_POINTER_DIMENSION / 2 - ((xHot+15) & 0xFFFFFFF0L)) / 4);
cxWhole = cx / 16; // Each word accounts for 16 pels
xHotWordBnd = xHot % 16;
if(xHotWordBnd) { ulTransp >>= (16 - xHotWordBnd); cxWhole *= 2; for (i = cy; i != 0; i--) { pbSrc = pjSrcScan; pbDst = pjDstScan;
ulPreviousData = ulTransp << 16;
for (j = 0; j < cxWhole; j++, pbSrc++) { ulData = (ULONG) (*pbSrc); ulData <<= (8 + xHotWordBnd); ulData |= ulPreviousData;
ucTemp = (UCHAR)(ulData >> 24); *pbDst = ucTemp;
pbDst += (j % 2 ? 3 : 1);
// next byte
ulData <<= 8; ulPreviousData = ulData;
}
// last word
ulData |= ulTransp; ucTemp = (UCHAR)(ulData >> 24); *pbDst = ucTemp;
pbDst += (2*j + 1); ucTemp = (UCHAR)(ulData >> 16); *pbDst = ucTemp;
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; }
} else { for (i = cy; i != 0; i--) { pwSrc = (WORD*) pjSrcScan; pwDst = (WORD*) pjDstScan;
for (j = cxWhole; j != 0; j--) { *pwDst = *pwSrc; pwSrc += 1; // Go to next word in source mask
pwDst += 2; // Skip over the XOR word in the dest mask
}
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; } }
// Now handle the XOR mask:
pjDstScan = (BYTE *) pBuf; pjDstScan += (2 + (HW_POINTER_DIMENSION / 2 - yHot) * lDstDelta + (HW_POINTER_DIMENSION / 2 - ((xHot+15) & 0xFFFFFFF0L)) / 4);
if(xHotWordBnd) { for (i = cy; i != 0; i--) { pbSrc = pjSrcScan; pbDst = pjDstScan;
ulPreviousData = 0;
for (j = 0; j < cxWhole; j++, pbSrc++) { ulData = (ULONG) (*pbSrc); ulData <<= (8 + xHotWordBnd); ulData |= ulPreviousData;
ucTemp = (UCHAR)(ulData >> 24); *pbDst = ucTemp;
pbDst += (j % 2 ? 3 : 1);
// Next byte
ulData <<= 8; ulPreviousData = ulData;
}
ucTemp = (UCHAR)(ulData >> 24); *pbDst = ucTemp;
pbDst += (2*j + 1); ucTemp = (UCHAR)(ulData >> 16); *pbDst = ucTemp;
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; } } else {
for (i = cy; i != 0; i--) { pwSrc = (WORD*) pjSrcScan; pwDst = (WORD*) pjDstScan;
for (j = cxWhole; j != 0; j--) { *pwDst = *pwSrc; pwSrc += 1; // Go to next word in source mask
pwDst += 2; // Skip over the AND word in the dest mask
}
pjSrcScan += lSrcDelta; pjDstScan += lDstDelta; } }
ACQUIRE_CRTC_CRITICAL_SECTION(ppdev);
pulSrc = (ULONG*) pBuf; pulDst = (ULONG*) ppdev->pvPointerShape;
if (DIRECT_ACCESS(ppdev)) { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { *pulDst++ = *pulSrc++; } } else { for (i = HW_POINTER_TOTAL_SIZE / sizeof(ULONG); i != 0; i--) { WRITE_REGISTER_ULONG(pulDst, *pulSrc); pulSrc++; pulDst++; } }
if(x >= 0) { if (!ppdev->bHwPointerActive) { ppdev->bHwPointerActive = TRUE; vShowPointerS3(ppdev, TRUE); } } else { if (ppdev->bHwPointerActive) { ppdev->bHwPointerActive = FALSE; vShowPointerS3(ppdev, FALSE); } }
RELEASE_CRTC_CRITICAL_SECTION(ppdev);
// fix the hot spot at the center of the HW cursor
ppdev->xPointerHot = HW_POINTER_DIMENSION / 2; ppdev->yPointerHot = HW_POINTER_DIMENSION / 2;
return(SPS_ACCEPT_NOEXCLUDE);
}
|