/******************************Module*Header*******************************\ * Module Name: hardware.c * * Contains all the code that touches the display hardware. * * Copyright (c) 1994-1995 Microsoft Corporation \**************************************************************************/ #include "precomp.h" // Values for the internal, EGA-compatible palette. static WORD gPaletteBuffer[] = { 16, // 16 entries 0, // start with first palette register // On the VGA, the palette contains indices into the array of color DACs. // Since we can program the DACs as we please, we'll just put all the indices // down at the beginning of the DAC array (that is, pass pixel values through // the internal palette unchanged). 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // These are the values for the first 16 DAC registers, the only ones we'll // work with. These correspond to the RGB colors (6 bits for each primary, with // the fourth entry unused) for pixel values 0-15. static BYTE gColorBuffer[] = { 16, // 16 entries 0, 0, 0, // start with first palette register 0x00, 0x00, 0x00, 0x00, // black 0x2A, 0x00, 0x15, 0x00, // red 0x00, 0x2A, 0x15, 0x00, // green 0x2A, 0x2A, 0x15, 0x00, // mustard/brown 0x00, 0x00, 0x2A, 0x00, // blue 0x2A, 0x15, 0x2A, 0x00, // magenta 0x15, 0x2A, 0x2A, 0x00, // cyan 0x21, 0x22, 0x23, 0x00, // dark gray 2A 0x30, 0x31, 0x32, 0x00, // light gray 39 0x3F, 0x00, 0x00, 0x00, // bright red 0x00, 0x3F, 0x00, 0x00, // bright green 0x3F, 0x3F, 0x00, 0x00, // bright yellow 0x00, 0x00, 0x3F, 0x00, // bright blue 0x3F, 0x00, 0x3F, 0x00, // bright magenta 0x00, 0x3F, 0x3F, 0x00, // bright cyan 0x3F, 0x3F, 0x3F, 0x00 // bright white }; /******************************Public*Routine******************************\ * BOOL bAssertModeHardware * * Sets the appropriate hardware state for graphics mode or full-screen. * \**************************************************************************/ BOOL bAssertModeHardware( PDEV* ppdev, BOOL bEnable) { DWORD ReturnedDataLength; BYTE* pjBase; pjBase = ppdev->pjBase; if (bEnable) { // Set the desired mode. if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_CURRENT_MODE, &ppdev->ulMode, // input buffer sizeof(VIDEO_MODE), NULL, 0, &ReturnedDataLength)) { DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_CURRENT_MODE")); goto ReturnFalse; } // Set up the internal palette. if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_PALETTE_REGISTERS, (PVOID) gPaletteBuffer, // input buffer sizeof(gPaletteBuffer), NULL, // output buffer 0, &ReturnedDataLength)) { DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_PALETTE_REGISTERS")); return(FALSE); } // Set up the DAC. if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_COLOR_REGISTERS, (PVOID) gColorBuffer, // input buffer sizeof(gColorBuffer), NULL, // output buffer 0, &ReturnedDataLength)) { DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_COLOR_REGISTERS")); return(FALSE); } // Initialize sequencer to its defaults (all planes enabled, index // pointing to Map Mask). OUT_WORD(pjBase, VGA_BASE + SEQ_ADDR, (MM_ALL << 8) + SEQ_MAP_MASK); // Initialize graphics controller to its defaults (set/reset disabled for // all planes, no rotation & ALU function == replace, write mode 0 & read // mode 0, color compare ignoring all planes (read mode 1 reads always // return 0ffh, handy for ANDing), and the bit mask == 0ffh, gating all // bytes from the CPU. OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, GRAF_ENAB_SR); OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, (DR_SET << 8) + GRAF_DATA_ROT); OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, ((M_PROC_WRITE | M_DATA_READ) << 8) + GRAF_MODE); OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, GRAF_CDC); OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, (0xffL << 8) + GRAF_BIT_MASK); DISPDBG((5, "Passed bAssertModeHardware")); } else { // Call the kernel driver to reset the device to a known state. // NTVDM will take things from there: if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_RESET_DEVICE, NULL, 0, NULL, 0, &ReturnedDataLength)) { DISPDBG((0, "bAssertModeHardware - Failed reset IOCTL")); goto ReturnFalse; } } return(TRUE); ReturnFalse: DISPDBG((0, "Failed bAssertModeHardware")); return(FALSE); } /******************************Public*Routine******************************\ * BOOL bEnableHardware * * Puts the hardware into the requested mode and initializes it. * * Note: Should be called before any access is done to the hardware from * the display driver. * \**************************************************************************/ BOOL bEnableHardware( PDEV* ppdev) { VIDEO_MEMORY VideoMemory; VIDEO_MEMORY_INFORMATION VideoMemoryInfo; VIDEO_MODE_INFORMATION VideoModeInfo; DWORD ReturnedDataLength; VIDEO_PUBLIC_ACCESS_RANGES VideoAccessRange; DWORD status; // Map io ports into virtual memory: VideoMemory.RequestedVirtualAddress = NULL; if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES, NULL, // input buffer 0, &VideoAccessRange, // output buffer sizeof (VideoAccessRange), &ReturnedDataLength)) { DISPDBG((0, "bEnableHardware - Initialization error mapping IO port base")); goto ReturnFalse; } ppdev->pjBase = (UCHAR*) VideoAccessRange.VirtualAddress; // Set the desired mode. (Must come before IOCTL_VIDEO_MAP_VIDEO_MEMORY; // that IOCTL returns information for the current mode, so there must be a // current mode for which to return information.) if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SET_CURRENT_MODE, &ppdev->ulMode, // input buffer sizeof(VIDEO_MODE), NULL, 0, &ReturnedDataLength)) { DISPDBG((0, "bEnableHardware - Set current mode")); goto ReturnFalse; } // Get the linear memory address range. VideoMemory.RequestedVirtualAddress = NULL; if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &VideoMemory, // input buffer sizeof(VIDEO_MEMORY), &VideoMemoryInfo, // output buffer sizeof(VideoMemoryInfo), &ReturnedDataLength)) { DISPDBG((0, "bEnableHardware - Error mapping buffer address")); goto ReturnFalse; } DISPDBG((1, "FrameBufferBase: %lx", VideoMemoryInfo.FrameBufferBase)); // Record the Frame Buffer Linear Address. ppdev->pjScreen = (BYTE*) VideoMemoryInfo.FrameBufferBase; if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_QUERY_CURRENT_MODE, NULL, 0, &VideoModeInfo, sizeof(VideoModeInfo), &ReturnedDataLength)) { DISPDBG((0, "bEnableHardware - failed VIDEO_QUERY_CURRENT_MODE")); goto ReturnFalse; } // Store the width of the screen in bytes ppdev->lDelta = VideoModeInfo.ScreenStride; if (!bAssertModeHardware(ppdev, TRUE)) goto ReturnFalse; DISPDBG((5, "Passed bEnableHardware")); return(TRUE); ReturnFalse: DISPDBG((0, "Failed bEnableHardware")); return(FALSE); } /******************************Public*Routine******************************\ * VOID vDisableHardware * * Undoes anything done in bEnableHardware. * * Note: In an error case, we may call this before bEnableHardware is * completely done. * \**************************************************************************/ VOID vDisableHardware( PDEV* ppdev) { DWORD ReturnedDataLength; VIDEO_MEMORY VideoMemory; if ((VideoMemory.RequestedVirtualAddress = ppdev->pjScreen) != NULL) { if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_UNMAP_VIDEO_MEMORY, &VideoMemory, sizeof(VIDEO_MEMORY), NULL, 0, &ReturnedDataLength)) { DISPDBG((0, "vDisableHardware failed IOCTL_VIDEO_UNMAP_VIDEO")); } } if((VideoMemory.RequestedVirtualAddress = ppdev->pjBase) != INVALID_BASE_ADDRESS) { if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES, &VideoMemory, sizeof(VIDEO_MEMORY), NULL, 0, &ReturnedDataLength)) { DISPDBG((0, "vDisableHardware failed IOCTL_VIDEO_FREE_PUBLIC_ACCESS")); } ppdev->pjBase = INVALID_BASE_ADDRESS; } } /******************************Public*Routine******************************\ * VOID vUpdate(ppdev, prcl, pco) * * Updates the screen from the DIB surface for the given rectangle. * Increases the rectangle size if necessary for easy alignment. * \**************************************************************************/ #define STRIP_SIZE 32 // This little macro returns the 'PositionInNibble' bit of the // 'NibbleNumber' nibble of the given 'Dword', and aligns it so that // it's in the 'PositionInResult' bit of the result. Numbering is done // in the order '7 6 5 4 3 2 1 0'. // // Given constants for everything but 'Dword', this will amount to an // AND and a SHIFT. #define BITPOS(Dword, PositionInNibble, NibbleNumber, PositionInResult) \ (WORD) (((((PositionInNibble) + (NibbleNumber) * 4) > (PositionInResult)) ? \ (((Dword) & (1 << ((PositionInNibble) + (NibbleNumber) * 4))) \ >> ((PositionInNibble) + (NibbleNumber) * 4 - (PositionInResult))) : \ (((Dword) & (1 << ((PositionInNibble) + (NibbleNumber) * 4))) \ << ((PositionInResult) - (PositionInNibble) - (NibbleNumber) * 4)))) VOID vUpdate(PDEV* ppdev, RECTL* prcl, CLIPOBJ* pco) { BYTE* pjBase; RECTL rcl; SURFOBJ* pso; LONG cy; LONG cyThis; LONG cw; ULONG* pulSrcStart; ULONG* pulSrc; WORD* pwDstStart; WORD* pwDst; LONG i; LONG j; ULONG ul; WORD w; LONG lSrcDelta; LONG lDstDelta; LONG lSrcSkip; LONG lDstSkip; pjBase = ppdev->pjBase; if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL)) { // We have to clip to the screen dimensions because we may have // been a bit loose when we guessed the bounds of the drawing: rcl.left = max(0, prcl->left); rcl.top = max(0, prcl->top); rcl.right = min(ppdev->cxScreen, prcl->right); rcl.bottom = min(ppdev->cyScreen, prcl->bottom); } else { // We may as well save ourselves some blting by clipping to // the clip object's maximum extent. The clip object's bounds // are guaranteed to be contained within the dimensions of the // screen: rcl.left = max(pco->rclBounds.left, prcl->left); rcl.top = max(pco->rclBounds.top, prcl->top); rcl.right = min(pco->rclBounds.right, prcl->right); rcl.bottom = min(pco->rclBounds.bottom, prcl->bottom); } // Be paranoid: if ((rcl.left >= rcl.right) || (rcl.top >= rcl.bottom)) return; // Align to words so that we don't have to do any read-modify-write // operations. rcl.left = (rcl.left) & ~15; rcl.right = (rcl.right + 15) & ~15; pso = ppdev->pso; lSrcDelta = pso->lDelta; pulSrcStart = (ULONG*) ((BYTE*) pso->pvScan0 + (rcl.top * lSrcDelta) + (rcl.left >> 1)); lDstDelta = ppdev->lDelta; pwDstStart = (WORD*) (ppdev->pjScreen + (rcl.top * lDstDelta) + (rcl.left >> 3)); cy = (rcl.bottom - rcl.top); cw = (rcl.right - rcl.left) >> 4; lSrcSkip = lSrcDelta - (8 * cw); lDstSkip = lDstDelta - (2 * cw); do { cyThis = STRIP_SIZE; cy -= STRIP_SIZE; if (cy < 0) cyThis += cy; // Map in plane 0: OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C0); pwDst = pwDstStart; pulSrc = pulSrcStart; for (j = cyThis; j != 0; j--) { for (i = cw; i != 0; i--) { ul = *(pulSrc); w = BITPOS(ul, 0, 6, 0) | BITPOS(ul, 0, 7, 1) | BITPOS(ul, 0, 4, 2) | BITPOS(ul, 0, 5, 3) | BITPOS(ul, 0, 2, 4) | BITPOS(ul, 0, 3, 5) | BITPOS(ul, 0, 0, 6) | BITPOS(ul, 0, 1, 7); ul = *(pulSrc + 1); w |= BITPOS(ul, 0, 6, 8) | BITPOS(ul, 0, 7, 9) | BITPOS(ul, 0, 4, 10) | BITPOS(ul, 0, 5, 11) | BITPOS(ul, 0, 2, 12) | BITPOS(ul, 0, 3, 13) | BITPOS(ul, 0, 0, 14) | BITPOS(ul, 0, 1, 15); WRITE_WORD(pwDst, w); pwDst += 1; pulSrc += 2; } pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } // Map in plane 1: OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C1); pwDst = pwDstStart; pulSrc = pulSrcStart; for (j = cyThis; j != 0; j--) { for (i = cw; i != 0; i--) { ul = *(pulSrc); w = BITPOS(ul, 1, 6, 0) | BITPOS(ul, 1, 7, 1) | BITPOS(ul, 1, 4, 2) | BITPOS(ul, 1, 5, 3) | BITPOS(ul, 1, 2, 4) | BITPOS(ul, 1, 3, 5) | BITPOS(ul, 1, 0, 6) | BITPOS(ul, 1, 1, 7); ul = *(pulSrc + 1); w |= BITPOS(ul, 1, 6, 8) | BITPOS(ul, 1, 7, 9) | BITPOS(ul, 1, 4, 10) | BITPOS(ul, 1, 5, 11) | BITPOS(ul, 1, 2, 12) | BITPOS(ul, 1, 3, 13) | BITPOS(ul, 1, 0, 14) | BITPOS(ul, 1, 1, 15); WRITE_WORD(pwDst, w); pwDst += 1; pulSrc += 2; } pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } // Map in plane 2: OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C2); pwDst = pwDstStart; pulSrc = pulSrcStart; for (j = cyThis; j != 0; j--) { for (i = cw; i != 0; i--) { ul = *(pulSrc); w = BITPOS(ul, 2, 6, 0) | BITPOS(ul, 2, 7, 1) | BITPOS(ul, 2, 4, 2) | BITPOS(ul, 2, 5, 3) | BITPOS(ul, 2, 2, 4) | BITPOS(ul, 2, 3, 5) | BITPOS(ul, 2, 0, 6) | BITPOS(ul, 2, 1, 7); ul = *(pulSrc + 1); w |= BITPOS(ul, 2, 6, 8) | BITPOS(ul, 2, 7, 9) | BITPOS(ul, 2, 4, 10) | BITPOS(ul, 2, 5, 11) | BITPOS(ul, 2, 2, 12) | BITPOS(ul, 2, 3, 13) | BITPOS(ul, 2, 0, 14) | BITPOS(ul, 2, 1, 15); WRITE_WORD(pwDst, w); pwDst += 1; pulSrc += 2; } pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } // Map in plane 3: OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C3); pwDst = pwDstStart; pulSrc = pulSrcStart; for (j = cyThis; j != 0; j--) { for (i = cw; i != 0; i--) { ul = *(pulSrc); w = BITPOS(ul, 3, 6, 0) | BITPOS(ul, 3, 7, 1) | BITPOS(ul, 3, 4, 2) | BITPOS(ul, 3, 5, 3) | BITPOS(ul, 3, 2, 4) | BITPOS(ul, 3, 3, 5) | BITPOS(ul, 3, 0, 6) | BITPOS(ul, 3, 1, 7); ul = *(pulSrc + 1); w |= BITPOS(ul, 3, 6, 8) | BITPOS(ul, 3, 7, 9) | BITPOS(ul, 3, 4, 10) | BITPOS(ul, 3, 5, 11) | BITPOS(ul, 3, 2, 12) | BITPOS(ul, 3, 3, 13) | BITPOS(ul, 3, 0, 14) | BITPOS(ul, 3, 1, 15); WRITE_WORD(pwDst, w); pwDst += 1; pulSrc += 2; } pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip); pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip); } // Get ready for next strip: pulSrcStart = (ULONG*) ((BYTE*) pulSrcStart + (cyThis * lSrcDelta)); pwDstStart = (WORD*) ((BYTE*) pwDstStart + (cyThis * lDstDelta)); } while (cy > 0); }