/* * * Copyright 1991-1999 by The XFree86 Project, Inc. * * Loosely based on code bearing the following copyright: * * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * */ #define _NEED_SYSI86 #ifdef HAVE_XORG_CONFIG_H #include #endif #include #include #include #include #include "misc.h" #include "xf86.h" #include "xf86_OSproc.h" #include "vgaHW.h" #include "compiler.h" #include "xf86cmap.h" #include "Pci.h" #ifndef SAVE_FONT1 #define SAVE_FONT1 1 #endif /* * These used to be OS-specific, which made this module have an undesirable * OS dependency. Define them by default for all platforms. */ #ifndef NEED_SAVED_CMAP #define NEED_SAVED_CMAP #endif #ifndef SAVE_TEXT #define SAVE_TEXT 1 #endif #ifndef SAVE_FONT2 #define SAVE_FONT2 1 #endif /* bytes per plane to save for text */ #define TEXT_AMOUNT 16384 /* bytes per plane to save for font data */ #define FONT_AMOUNT (8*8192) #if 0 /* Override all of these for now */ #undef SAVE_FONT1 #define SAVE_FONT1 1 #undef SAVE_FONT2 #define SAVE_FONT2 1 #undef SAVE_TEST #define SAVE_TEST 1 #undef FONT_AMOUNT #define FONT_AMOUNT 65536 #undef TEXT_AMOUNT #define TEXT_AMOUNT 65536 #endif /* DAC indices for white and black */ #define WHITE_VALUE 0x3F #define BLACK_VALUE 0x00 #define OVERSCAN_VALUE 0x01 /* Use a private definition of this here */ #undef VGAHWPTR #define VGAHWPTRLVAL(p) (p)->privates[vgaHWPrivateIndex].ptr #define VGAHWPTR(p) ((vgaHWPtr)(VGAHWPTRLVAL(p))) static int vgaHWPrivateIndex = -1; #define DAC_TEST_MASK 0x3F #ifdef NEED_SAVED_CMAP /* This default colourmap is used only when it can't be read from the VGA */ static CARD8 defaultDAC[768] = { 0, 0, 0, 0, 0, 42, 0, 42, 0, 0, 42, 42, 42, 0, 0, 42, 0, 42, 42, 21, 0, 42, 42, 42, 21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63, 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63, 0, 0, 0, 5, 5, 5, 8, 8, 8, 11, 11, 11, 14, 14, 14, 17, 17, 17, 20, 20, 20, 24, 24, 24, 28, 28, 28, 32, 32, 32, 36, 36, 36, 40, 40, 40, 45, 45, 45, 50, 50, 50, 56, 56, 56, 63, 63, 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, 63, 63, 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, 0, 0, 63, 0, 0, 63, 16, 0, 63, 31, 0, 63, 47, 0, 63, 63, 0, 47, 63, 0, 31, 63, 0, 16, 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, 63, 63, 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, 31, 31, 63, 31, 31, 63, 39, 31, 63, 47, 31, 63, 55, 31, 63, 63, 31, 55, 63, 31, 47, 63, 31, 39, 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, 63, 63, 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, 45, 45, 63, 45, 45, 63, 49, 45, 63, 54, 45, 63, 58, 45, 63, 63, 45, 58, 63, 45, 54, 63, 45, 49, 63, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, 28, 28, 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, 0, 0, 28, 0, 0, 28, 7, 0, 28, 14, 0, 28, 21, 0, 28, 28, 0, 21, 28, 0, 14, 28, 0, 7, 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, 28, 28, 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, 14, 14, 28, 14, 14, 28, 17, 14, 28, 21, 14, 28, 24, 14, 28, 28, 14, 24, 28, 14, 21, 28, 14, 17, 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, 28, 28, 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, 20, 20, 28, 20, 20, 28, 22, 20, 28, 24, 20, 28, 26, 20, 28, 28, 20, 26, 28, 20, 24, 28, 20, 22, 28, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, 16, 16, 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, 0, 0, 16, 0, 0, 16, 4, 0, 16, 8, 0, 16, 12, 0, 16, 16, 0, 12, 16, 0, 8, 16, 0, 4, 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, 16, 16, 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, 8, 8, 16, 8, 8, 16, 10, 8, 16, 12, 8, 16, 14, 8, 16, 16, 8, 14, 16, 8, 12, 16, 8, 10, 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, 16, 16, 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, 11, 11, 16, 11, 11, 16, 12, 11, 16, 13, 11, 16, 15, 11, 16, 16, 11, 15, 16, 11, 13, 16, 11, 12, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #endif /* NEED_SAVED_CMAP */ /* * Standard VGA versions of the register access functions. */ static void stdWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) { pci_io_write8(hwp->io, hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); pci_io_write8(hwp->io, hwp->IOBase + VGA_CRTC_DATA_OFFSET, value); } static CARD8 stdReadCrtc(vgaHWPtr hwp, CARD8 index) { pci_io_write8(hwp->io, hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); return pci_io_read8(hwp->io, hwp->IOBase + VGA_CRTC_DATA_OFFSET); } static void stdWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) { pci_io_write8(hwp->io, VGA_GRAPH_INDEX, index); pci_io_write8(hwp->io, VGA_GRAPH_DATA, value); } static CARD8 stdReadGr(vgaHWPtr hwp, CARD8 index) { pci_io_write8(hwp->io, VGA_GRAPH_INDEX, index); return pci_io_read8(hwp->io, VGA_GRAPH_DATA); } static void stdWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) { pci_io_write8(hwp->io, VGA_SEQ_INDEX, index); pci_io_write8(hwp->io, VGA_SEQ_DATA, value); } static CARD8 stdReadSeq(vgaHWPtr hwp, CARD8 index) { pci_io_write8(hwp->io, VGA_SEQ_INDEX, index); return pci_io_read8(hwp->io, VGA_SEQ_DATA); } static CARD8 stdReadST00(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_IN_STAT_0); } static CARD8 stdReadST01(vgaHWPtr hwp) { return pci_io_read8(hwp->io, hwp->IOBase + VGA_IN_STAT_1_OFFSET); } static CARD8 stdReadFCR(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_FEATURE_R); } static void stdWriteFCR(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, hwp->IOBase + VGA_FEATURE_W_OFFSET, value); } static void stdWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) { if (hwp->paletteEnabled) index &= ~0x20; else index |= 0x20; (void) pci_io_read8(hwp->io, hwp->IOBase + VGA_IN_STAT_1_OFFSET); pci_io_write8(hwp->io, VGA_ATTR_INDEX, index); pci_io_write8(hwp->io, VGA_ATTR_DATA_W, value); } static CARD8 stdReadAttr(vgaHWPtr hwp, CARD8 index) { if (hwp->paletteEnabled) index &= ~0x20; else index |= 0x20; (void) pci_io_read8(hwp->io, hwp->IOBase + VGA_IN_STAT_1_OFFSET); pci_io_write8(hwp->io, VGA_ATTR_INDEX, index); return pci_io_read8(hwp->io, VGA_ATTR_DATA_R); } static void stdWriteMiscOut(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_MISC_OUT_W, value); } static CARD8 stdReadMiscOut(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_MISC_OUT_R); } static void stdEnablePalette(vgaHWPtr hwp) { (void) pci_io_read8(hwp->io, hwp->IOBase + VGA_IN_STAT_1_OFFSET); pci_io_write8(hwp->io, VGA_ATTR_INDEX, 0x00); hwp->paletteEnabled = TRUE; } static void stdDisablePalette(vgaHWPtr hwp) { (void) pci_io_read8(hwp->io, hwp->IOBase + VGA_IN_STAT_1_OFFSET); pci_io_write8(hwp->io, VGA_ATTR_INDEX, 0x20); hwp->paletteEnabled = FALSE; } static void stdWriteDacMask(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_DAC_MASK, value); } static CARD8 stdReadDacMask(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_DAC_MASK); } static void stdWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_DAC_READ_ADDR, value); } static void stdWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_DAC_WRITE_ADDR, value); } static void stdWriteDacData(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_DAC_DATA, value); } static CARD8 stdReadDacData(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_DAC_DATA); } static CARD8 stdReadEnable(vgaHWPtr hwp) { return pci_io_read8(hwp->io, VGA_ENABLE); } static void stdWriteEnable(vgaHWPtr hwp, CARD8 value) { pci_io_write8(hwp->io, VGA_ENABLE, value); } void vgaHWSetStdFuncs(vgaHWPtr hwp) { hwp->writeCrtc = stdWriteCrtc; hwp->readCrtc = stdReadCrtc; hwp->writeGr = stdWriteGr; hwp->readGr = stdReadGr; hwp->readST00 = stdReadST00; hwp->readST01 = stdReadST01; hwp->readFCR = stdReadFCR; hwp->writeFCR = stdWriteFCR; hwp->writeAttr = stdWriteAttr; hwp->readAttr = stdReadAttr; hwp->writeSeq = stdWriteSeq; hwp->readSeq = stdReadSeq; hwp->writeMiscOut = stdWriteMiscOut; hwp->readMiscOut = stdReadMiscOut; hwp->enablePalette = stdEnablePalette; hwp->disablePalette = stdDisablePalette; hwp->writeDacMask = stdWriteDacMask; hwp->readDacMask = stdReadDacMask; hwp->writeDacWriteAddr = stdWriteDacWriteAddr; hwp->writeDacReadAddr = stdWriteDacReadAddr; hwp->writeDacData = stdWriteDacData; hwp->readDacData = stdReadDacData; hwp->readEnable = stdReadEnable; hwp->writeEnable = stdWriteEnable; hwp->io = pci_legacy_open_io(hwp->dev, 0, 64 * 1024); } /* * MMIO versions of the register access functions. These require * hwp->MemBase to be set in such a way that when the standard VGA port * adderss is added the correct memory address results. */ #define minb(p) MMIO_IN8(hwp->MMIOBase, (hwp->MMIOOffset + (p))) #define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (hwp->MMIOOffset + (p)),(v)) static void mmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value) { moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); moutb(hwp->IOBase + VGA_CRTC_DATA_OFFSET, value); } static CARD8 mmioReadCrtc(vgaHWPtr hwp, CARD8 index) { moutb(hwp->IOBase + VGA_CRTC_INDEX_OFFSET, index); return minb(hwp->IOBase + VGA_CRTC_DATA_OFFSET); } static void mmioWriteGr(vgaHWPtr hwp, CARD8 index, CARD8 value) { moutb(VGA_GRAPH_INDEX, index); moutb(VGA_GRAPH_DATA, value); } static CARD8 mmioReadGr(vgaHWPtr hwp, CARD8 index) { moutb(VGA_GRAPH_INDEX, index); return minb(VGA_GRAPH_DATA); } static void mmioWriteSeq(vgaHWPtr hwp, CARD8 index, CARD8 value) { moutb(VGA_SEQ_INDEX, index); moutb(VGA_SEQ_DATA, value); } static CARD8 mmioReadSeq(vgaHWPtr hwp, CARD8 index) { moutb(VGA_SEQ_INDEX, index); return minb(VGA_SEQ_DATA); } static CARD8 mmioReadST00(vgaHWPtr hwp) { return minb(VGA_IN_STAT_0); } static CARD8 mmioReadST01(vgaHWPtr hwp) { return minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); } static CARD8 mmioReadFCR(vgaHWPtr hwp) { return minb(VGA_FEATURE_R); } static void mmioWriteFCR(vgaHWPtr hwp, CARD8 value) { moutb(hwp->IOBase + VGA_FEATURE_W_OFFSET, value); } static void mmioWriteAttr(vgaHWPtr hwp, CARD8 index, CARD8 value) { if (hwp->paletteEnabled) index &= ~0x20; else index |= 0x20; (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); moutb(VGA_ATTR_INDEX, index); moutb(VGA_ATTR_DATA_W, value); } static CARD8 mmioReadAttr(vgaHWPtr hwp, CARD8 index) { if (hwp->paletteEnabled) index &= ~0x20; else index |= 0x20; (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); moutb(VGA_ATTR_INDEX, index); return minb(VGA_ATTR_DATA_R); } static void mmioWriteMiscOut(vgaHWPtr hwp, CARD8 value) { moutb(VGA_MISC_OUT_W, value); } static CARD8 mmioReadMiscOut(vgaHWPtr hwp) { return minb(VGA_MISC_OUT_R); } static void mmioEnablePalette(vgaHWPtr hwp) { (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); moutb(VGA_ATTR_INDEX, 0x00); hwp->paletteEnabled = TRUE; } static void mmioDisablePalette(vgaHWPtr hwp) { (void) minb(hwp->IOBase + VGA_IN_STAT_1_OFFSET); moutb(VGA_ATTR_INDEX, 0x20); hwp->paletteEnabled = FALSE; } static void mmioWriteDacMask(vgaHWPtr hwp, CARD8 value) { moutb(VGA_DAC_MASK, value); } static CARD8 mmioReadDacMask(vgaHWPtr hwp) { return minb(VGA_DAC_MASK); } static void mmioWriteDacReadAddr(vgaHWPtr hwp, CARD8 value) { moutb(VGA_DAC_READ_ADDR, value); } static void mmioWriteDacWriteAddr(vgaHWPtr hwp, CARD8 value) { moutb(VGA_DAC_WRITE_ADDR, value); } static void mmioWriteDacData(vgaHWPtr hwp, CARD8 value) { moutb(VGA_DAC_DATA, value); } static CARD8 mmioReadDacData(vgaHWPtr hwp) { return minb(VGA_DAC_DATA); } static CARD8 mmioReadEnable(vgaHWPtr hwp) { return minb(VGA_ENABLE); } static void mmioWriteEnable(vgaHWPtr hwp, CARD8 value) { moutb(VGA_ENABLE, value); } void vgaHWSetMmioFuncs(vgaHWPtr hwp, CARD8 *base, int offset) { hwp->writeCrtc = mmioWriteCrtc; hwp->readCrtc = mmioReadCrtc; hwp->writeGr = mmioWriteGr; hwp->readGr = mmioReadGr; hwp->readST00 = mmioReadST00; hwp->readST01 = mmioReadST01; hwp->readFCR = mmioReadFCR; hwp->writeFCR = mmioWriteFCR; hwp->writeAttr = mmioWriteAttr; hwp->readAttr = mmioReadAttr; hwp->writeSeq = mmioWriteSeq; hwp->readSeq = mmioReadSeq; hwp->writeMiscOut = mmioWriteMiscOut; hwp->readMiscOut = mmioReadMiscOut; hwp->enablePalette = mmioEnablePalette; hwp->disablePalette = mmioDisablePalette; hwp->writeDacMask = mmioWriteDacMask; hwp->readDacMask = mmioReadDacMask; hwp->writeDacWriteAddr = mmioWriteDacWriteAddr; hwp->writeDacReadAddr = mmioWriteDacReadAddr; hwp->writeDacData = mmioWriteDacData; hwp->readDacData = mmioReadDacData; hwp->MMIOBase = base; hwp->MMIOOffset = offset; hwp->readEnable = mmioReadEnable; hwp->writeEnable = mmioWriteEnable; } /* * vgaHWProtect -- * Protect VGA registers and memory from corruption during loads. */ void vgaHWProtect(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); unsigned char tmp; if (pScrn->vtSema) { if (on) { /* * Turn off screen and disable sequencer. */ tmp = hwp->readSeq(hwp, 0x01); vgaHWSeqReset(hwp, TRUE); /* start synchronous reset */ hwp->writeSeq(hwp, 0x01, tmp | 0x20); /* disable the display */ hwp->enablePalette(hwp); } else { /* * Reenable sequencer, then turn on screen. */ tmp = hwp->readSeq(hwp, 0x01); hwp->writeSeq(hwp, 0x01, tmp & ~0x20); /* reenable display */ vgaHWSeqReset(hwp, FALSE); /* clear synchronousreset */ hwp->disablePalette(hwp); } } } vgaHWProtectProc * vgaHWProtectWeak(void) { return vgaHWProtect; } /* * vgaHWBlankScreen -- blank the screen. */ void vgaHWBlankScreen(ScrnInfoPtr pScrn, Bool on) { vgaHWPtr hwp = VGAHWPTR(pScrn); unsigned char scrn; scrn = hwp->readSeq(hwp, 0x01); if (on) { scrn &= ~0x20; /* enable screen */ } else { scrn |= 0x20; /* blank screen */ } vgaHWSeqReset(hwp, TRUE); hwp->writeSeq(hwp, 0x01, scrn); /* change mode */ vgaHWSeqReset(hwp, FALSE); } vgaHWBlankScreenProc * vgaHWBlankScreenWeak(void) { return vgaHWBlankScreen; } /* * vgaHWSaveScreen -- blank the screen. */ Bool vgaHWSaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = NULL; Bool on; if (pScreen != NULL) pScrn = xf86Screens[pScreen->myNum]; on = xf86IsUnblank(mode); #if 0 if (on) SetTimeSinceLastInputEvent(); #endif if ((pScrn != NULL) && pScrn->vtSema) { vgaHWBlankScreen(pScrn, on); } return TRUE; } /* * vgaHWDPMSSet -- Sets VESA Display Power Management Signaling (DPMS) Mode * * This generic VGA function can only set the Off and On modes. If the * Standby and Suspend modes are to be supported, a chip specific replacement * for this function must be written. */ void vgaHWDPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { unsigned char seq1 = 0, crtc17 = 0; vgaHWPtr hwp = VGAHWPTR(pScrn); if (!pScrn->vtSema) return; switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ seq1 = 0x00; crtc17 = 0x80; break; case DPMSModeStandby: /* Screen: Off; HSync: Off, VSync: On -- Not Supported */ seq1 = 0x20; crtc17 = 0x80; break; case DPMSModeSuspend: /* Screen: Off; HSync: On, VSync: Off -- Not Supported */ seq1 = 0x20; crtc17 = 0x80; break; case DPMSModeOff: /* Screen: Off; HSync: Off, VSync: Off */ seq1 = 0x20; crtc17 = 0x00; break; } hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ seq1 |= hwp->readSeq(hwp, 0x01) & ~0x20; hwp->writeSeq(hwp, 0x01, seq1); crtc17 |= hwp->readCrtc(hwp, 0x17) & ~0x80; usleep(10000); hwp->writeCrtc(hwp, 0x17, crtc17); hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ } /* * vgaHWSeqReset * perform a sequencer reset. */ void vgaHWSeqReset(vgaHWPtr hwp, Bool start) { if (start) hwp->writeSeq(hwp, 0x00, 0x01); /* Synchronous Reset */ else hwp->writeSeq(hwp, 0x00, 0x03); /* End Reset */ } void vgaHWRestoreFonts(ScrnInfoPtr scrninfp, vgaRegPtr restore) { #if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 vgaHWPtr hwp = VGAHWPTR(scrninfp); int savedIOBase; unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4; Bool doMap = FALSE; /* If nothing to do, return now */ if (!hwp->FontInfo1 && !hwp->FontInfo2 && !hwp->TextInfo) return; if (hwp->Base == NULL) { doMap = TRUE; if (!vgaHWMapMem(scrninfp)) { xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, "vgaHWRestoreFonts: vgaHWMapMem() failed\n"); return; } } /* save the registers that are needed here */ miscOut = hwp->readMiscOut(hwp); attr10 = hwp->readAttr(hwp, 0x10); gr1 = hwp->readGr(hwp, 0x01); gr3 = hwp->readGr(hwp, 0x03); gr4 = hwp->readGr(hwp, 0x04); gr5 = hwp->readGr(hwp, 0x05); gr6 = hwp->readGr(hwp, 0x06); gr8 = hwp->readGr(hwp, 0x08); seq2 = hwp->readSeq(hwp, 0x02); seq4 = hwp->readSeq(hwp, 0x04); /* save hwp->IOBase and temporarily set it for colour mode */ savedIOBase = hwp->IOBase; hwp->IOBase = VGA_IOBASE_COLOR; /* Force into colour mode */ hwp->writeMiscOut(hwp, miscOut | 0x01); vgaHWBlankScreen(scrninfp, FALSE); /* * here we temporarily switch to 16 colour planar mode, to simply * copy the font-info and saved text. * * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! */ #if 0 hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ #endif hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ if (scrninfp->depth == 4) { /* GJA */ hwp->writeGr(hwp, 0x03, 0x00); /* don't rotate, write unmodified */ hwp->writeGr(hwp, 0x08, 0xFF); /* write all bits in a byte */ hwp->writeGr(hwp, 0x01, 0x00); /* all planes come from CPU */ } #if SAVE_FONT1 if (hwp->FontInfo1) { hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ slowbcopy_tobus(hwp->FontInfo1, hwp->Base, FONT_AMOUNT); } #endif #if SAVE_FONT2 if (hwp->FontInfo2) { hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ slowbcopy_tobus(hwp->FontInfo2, hwp->Base, FONT_AMOUNT); } #endif #if SAVE_TEXT if (hwp->TextInfo) { hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ slowbcopy_tobus(hwp->TextInfo, hwp->Base, TEXT_AMOUNT); hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ slowbcopy_tobus((unsigned char *) hwp->TextInfo + TEXT_AMOUNT, hwp->Base, TEXT_AMOUNT); } #endif vgaHWBlankScreen(scrninfp, TRUE); /* restore the registers that were changed */ hwp->writeMiscOut(hwp, miscOut); hwp->writeAttr(hwp, 0x10, attr10); hwp->writeGr(hwp, 0x01, gr1); hwp->writeGr(hwp, 0x03, gr3); hwp->writeGr(hwp, 0x04, gr4); hwp->writeGr(hwp, 0x05, gr5); hwp->writeGr(hwp, 0x06, gr6); hwp->writeGr(hwp, 0x08, gr8); hwp->writeSeq(hwp, 0x02, seq2); hwp->writeSeq(hwp, 0x04, seq4); hwp->IOBase = savedIOBase; if (doMap) vgaHWUnmapMem(scrninfp); #endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ } void vgaHWRestoreMode(ScrnInfoPtr scrninfp, vgaRegPtr restore) { vgaHWPtr hwp = VGAHWPTR(scrninfp); int i; if (restore->MiscOutReg & 0x01) hwp->IOBase = VGA_IOBASE_COLOR; else hwp->IOBase = VGA_IOBASE_MONO; hwp->writeMiscOut(hwp, restore->MiscOutReg); for (i = 1; i < restore->numSequencer; i++) hwp->writeSeq(hwp, i, restore->Sequencer[i]); /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */ hwp->writeCrtc(hwp, 17, restore->CRTC[17] & ~0x80); for (i = 0; i < restore->numCRTC; i++) hwp->writeCrtc(hwp, i, restore->CRTC[i]); for (i = 0; i < restore->numGraphics; i++) hwp->writeGr(hwp, i, restore->Graphics[i]); hwp->enablePalette(hwp); for (i = 0; i < restore->numAttribute; i++) hwp->writeAttr(hwp, i, restore->Attribute[i]); hwp->disablePalette(hwp); } void vgaHWRestoreColormap(ScrnInfoPtr scrninfp, vgaRegPtr restore) { vgaHWPtr hwp = VGAHWPTR(scrninfp); int i; #if 0 hwp->enablePalette(hwp); #endif hwp->writeDacMask(hwp, 0xFF); hwp->writeDacWriteAddr(hwp, 0x00); for (i = 0; i < 768; i++) { hwp->writeDacData(hwp, restore->DAC[i]); DACDelay(hwp); } hwp->disablePalette(hwp); } /* * vgaHWRestore -- * restore the VGA state */ void vgaHWRestore(ScrnInfoPtr scrninfp, vgaRegPtr restore, int flags) { if (flags & VGA_SR_MODE) vgaHWRestoreMode(scrninfp, restore); if (flags & VGA_SR_FONTS) vgaHWRestoreFonts(scrninfp, restore); if (flags & VGA_SR_CMAP) vgaHWRestoreColormap(scrninfp, restore); } void vgaHWSaveFonts(ScrnInfoPtr scrninfp, vgaRegPtr save) { #if SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 vgaHWPtr hwp = VGAHWPTR(scrninfp); int savedIOBase; unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4; Bool doMap = FALSE; if (hwp->Base == NULL) { doMap = TRUE; if (!vgaHWMapMem(scrninfp)) { xf86DrvMsg(scrninfp->scrnIndex, X_ERROR, "vgaHWSaveFonts: vgaHWMapMem() failed\n"); return; } } /* If in graphics mode, don't save anything */ attr10 = hwp->readAttr(hwp, 0x10); if (attr10 & 0x01) return; /* save the registers that are needed here */ miscOut = hwp->readMiscOut(hwp); gr4 = hwp->readGr(hwp, 0x04); gr5 = hwp->readGr(hwp, 0x05); gr6 = hwp->readGr(hwp, 0x06); seq2 = hwp->readSeq(hwp, 0x02); seq4 = hwp->readSeq(hwp, 0x04); /* save hwp->IOBase and temporarily set it for colour mode */ savedIOBase = hwp->IOBase; hwp->IOBase = VGA_IOBASE_COLOR; /* Force into colour mode */ hwp->writeMiscOut(hwp, miscOut | 0x01); vgaHWBlankScreen(scrninfp, FALSE); /* * get the character sets, and text screen if required */ /* * Here we temporarily switch to 16 colour planar mode, to simply * copy the font-info * * BUG ALERT: The (S)VGA's segment-select register MUST be set correctly! */ #if 0 hwp->writeAttr(hwp, 0x10, 0x01); /* graphics mode */ #endif hwp->writeSeq(hwp, 0x04, 0x06); /* enable plane graphics */ hwp->writeGr(hwp, 0x05, 0x00); /* write mode 0, read mode 0 */ hwp->writeGr(hwp, 0x06, 0x05); /* set graphics */ #if SAVE_FONT1 if (hwp->FontInfo1 || (hwp->FontInfo1 = malloc(FONT_AMOUNT))) { hwp->writeSeq(hwp, 0x02, 0x04); /* write to plane 2 */ hwp->writeGr(hwp, 0x04, 0x02); /* read plane 2 */ slowbcopy_frombus(hwp->Base, hwp->FontInfo1, FONT_AMOUNT); } #endif /* SAVE_FONT1 */ #if SAVE_FONT2 if (hwp->FontInfo2 || (hwp->FontInfo2 = malloc(FONT_AMOUNT))) { hwp->writeSeq(hwp, 0x02, 0x08); /* write to plane 3 */ hwp->writeGr(hwp, 0x04, 0x03); /* read plane 3 */ slowbcopy_frombus(hwp->Base, hwp->FontInfo2, FONT_AMOUNT); } #endif /* SAVE_FONT2 */ #if SAVE_TEXT if (hwp->TextInfo || (hwp->TextInfo = malloc(2 * TEXT_AMOUNT))) { hwp->writeSeq(hwp, 0x02, 0x01); /* write to plane 0 */ hwp->writeGr(hwp, 0x04, 0x00); /* read plane 0 */ slowbcopy_frombus(hwp->Base, hwp->TextInfo, TEXT_AMOUNT); hwp->writeSeq(hwp, 0x02, 0x02); /* write to plane 1 */ hwp->writeGr(hwp, 0x04, 0x01); /* read plane 1 */ slowbcopy_frombus(hwp->Base, (unsigned char *) hwp->TextInfo + TEXT_AMOUNT, TEXT_AMOUNT); } #endif /* SAVE_TEXT */ /* Restore clobbered registers */ hwp->writeAttr(hwp, 0x10, attr10); hwp->writeSeq(hwp, 0x02, seq2); hwp->writeSeq(hwp, 0x04, seq4); hwp->writeGr(hwp, 0x04, gr4); hwp->writeGr(hwp, 0x05, gr5); hwp->writeGr(hwp, 0x06, gr6); hwp->writeMiscOut(hwp, miscOut); hwp->IOBase = savedIOBase; vgaHWBlankScreen(scrninfp, TRUE); if (doMap) vgaHWUnmapMem(scrninfp); #endif /* SAVE_TEXT || SAVE_FONT1 || SAVE_FONT2 */ } void vgaHWSaveMode(ScrnInfoPtr scrninfp, vgaRegPtr save) { vgaHWPtr hwp = VGAHWPTR(scrninfp); int i; save->MiscOutReg = hwp->readMiscOut(hwp); if (save->MiscOutReg & 0x01) hwp->IOBase = VGA_IOBASE_COLOR; else hwp->IOBase = VGA_IOBASE_MONO; for (i = 0; i < save->numCRTC; i++) { save->CRTC[i] = hwp->readCrtc(hwp, i); DebugF("CRTC[0x%02x] = 0x%02x\n", i, save->CRTC[i]); } hwp->enablePalette(hwp); for (i = 0; i < save->numAttribute; i++) { save->Attribute[i] = hwp->readAttr(hwp, i); DebugF("Attribute[0x%02x] = 0x%02x\n", i, save->Attribute[i]); } hwp->disablePalette(hwp); for (i = 0; i < save->numGraphics; i++) { save->Graphics[i] = hwp->readGr(hwp, i); DebugF("Graphics[0x%02x] = 0x%02x\n", i, save->Graphics[i]); } for (i = 1; i < save->numSequencer; i++) { save->Sequencer[i] = hwp->readSeq(hwp, i); DebugF("Sequencer[0x%02x] = 0x%02x\n", i, save->Sequencer[i]); } } void vgaHWSaveColormap(ScrnInfoPtr scrninfp, vgaRegPtr save) { vgaHWPtr hwp = VGAHWPTR(scrninfp); Bool readError = FALSE; int i; #ifdef NEED_SAVED_CMAP /* * Some ET4000 chips from 1991 have a HW bug that prevents the reading * of the color lookup table. Mask rev 9042EAI is known to have this bug. * * If the colourmap is not readable, we set the saved map to a default * map (taken from Ferraro's "Programmer's Guide to the EGA and VGA * Cards" 2nd ed). */ /* Only save it once */ if (hwp->cmapSaved) return; #if 0 hwp->enablePalette(hwp); #endif hwp->writeDacMask(hwp, 0xFF); /* * check if we can read the lookup table */ hwp->writeDacReadAddr(hwp, 0x00); for (i = 0; i < 6; i++) { save->DAC[i] = hwp->readDacData(hwp); switch (i % 3) { case 0: DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); break; case 1: DebugF("0x%02x, ", save->DAC[i]); break; case 2: DebugF("0x%02x\n", save->DAC[i]); } } /* * Check if we can read the palette - * use foreground color to prevent flashing. */ hwp->writeDacWriteAddr(hwp, 0x01); for (i = 3; i < 6; i++) hwp->writeDacData(hwp, ~save->DAC[i] & DAC_TEST_MASK); hwp->writeDacReadAddr(hwp, 0x01); for (i = 3; i < 6; i++) { if (hwp->readDacData(hwp) != (~save->DAC[i] & DAC_TEST_MASK)) readError = TRUE; } hwp->writeDacWriteAddr(hwp, 0x01); for (i = 3; i < 6; i++) hwp->writeDacData(hwp, save->DAC[i]); if (readError) { /* * save the default lookup table */ memmove(save->DAC, defaultDAC, 768); xf86DrvMsg(scrninfp->scrnIndex, X_WARNING, "Cannot read colourmap from VGA. Will restore with default\n"); } else { /* save the colourmap */ hwp->writeDacReadAddr(hwp, 0x02); for (i = 6; i < 768; i++) { save->DAC[i] = hwp->readDacData(hwp); DACDelay(hwp); switch (i % 3) { case 0: DebugF("DAC[0x%02x] = 0x%02x, ", i / 3, save->DAC[i]); break; case 1: DebugF("0x%02x, ", save->DAC[i]); break; case 2: DebugF("0x%02x\n", save->DAC[i]); } } } hwp->disablePalette(hwp); hwp->cmapSaved = TRUE; #endif } /* * vgaHWSave -- * save the current VGA state */ void vgaHWSave(ScrnInfoPtr scrninfp, vgaRegPtr save, int flags) { if (save == NULL) return; if (flags & VGA_SR_CMAP) vgaHWSaveColormap(scrninfp, save); if (flags & VGA_SR_MODE) vgaHWSaveMode(scrninfp, save); if (flags & VGA_SR_FONTS) vgaHWSaveFonts(scrninfp, save); } /* * vgaHWInit -- * Handle the initialization, etc. of a screen. * Return FALSE on failure. */ Bool vgaHWInit(ScrnInfoPtr scrninfp, DisplayModePtr mode) { unsigned int i; vgaHWPtr hwp; vgaRegPtr regp; int depth = scrninfp->depth; /* * make sure the vgaHWRec is allocated */ if (!vgaHWGetHWRec(scrninfp)) return FALSE; hwp = VGAHWPTR(scrninfp); regp = &hwp->ModeReg; /* * compute correct Hsync & Vsync polarity */ if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) && (mode->Flags & (V_PVSYNC | V_NVSYNC))) { regp->MiscOutReg = 0x23; if (mode->Flags & V_NHSYNC) regp->MiscOutReg |= 0x40; if (mode->Flags & V_NVSYNC) regp->MiscOutReg |= 0x80; } else { int VDisplay = mode->VDisplay; if (mode->Flags & V_DBLSCAN) VDisplay *= 2; if (mode->VScan > 1) VDisplay *= mode->VScan; if (VDisplay < 400) regp->MiscOutReg = 0xA3; /* +hsync -vsync */ else if (VDisplay < 480) regp->MiscOutReg = 0x63; /* -hsync +vsync */ else if (VDisplay < 768) regp->MiscOutReg = 0xE3; /* -hsync -vsync */ else regp->MiscOutReg = 0x23; /* +hsync +vsync */ } regp->MiscOutReg |= (mode->ClockIndex & 0x03) << 2; /* * Time Sequencer */ if (depth == 4) regp->Sequencer[0] = 0x02; else regp->Sequencer[0] = 0x00; if (mode->Flags & V_CLKDIV2) regp->Sequencer[1] = 0x09; else regp->Sequencer[1] = 0x01; if (depth == 1) regp->Sequencer[2] = 1 << BIT_PLANE; else regp->Sequencer[2] = 0x0F; regp->Sequencer[3] = 0x00; /* Font select */ if (depth < 8) regp->Sequencer[4] = 0x06; /* Misc */ else regp->Sequencer[4] = 0x0E; /* Misc */ /* * CRTC Controller */ regp->CRTC[0] = (mode->CrtcHTotal >> 3) - 5; regp->CRTC[1] = (mode->CrtcHDisplay >> 3) - 1; regp->CRTC[2] = (mode->CrtcHBlankStart >> 3) - 1; regp->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; i = (((mode->CrtcHSkew << 2) + 0x10) & ~0x1F); if (i < 0x80) regp->CRTC[3] |= i; regp->CRTC[4] = (mode->CrtcHSyncStart >> 3); regp->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) | (((mode->CrtcHSyncEnd >> 3)) & 0x1F); regp->CRTC[6] = (mode->CrtcVTotal - 2) & 0xFF; regp->CRTC[7] = (((mode->CrtcVTotal - 2) & 0x100) >> 8) | (((mode->CrtcVDisplay - 1) & 0x100) >> 7) | ((mode->CrtcVSyncStart & 0x100) >> 6) | (((mode->CrtcVBlankStart - 1) & 0x100) >> 5) | 0x10 | (((mode->CrtcVTotal - 2) & 0x200) >> 4) | (((mode->CrtcVDisplay - 1) & 0x200) >> 3) | ((mode->CrtcVSyncStart & 0x200) >> 2); regp->CRTC[8] = 0x00; regp->CRTC[9] = (((mode->CrtcVBlankStart - 1) & 0x200) >> 4) | 0x40; if (mode->Flags & V_DBLSCAN) regp->CRTC[9] |= 0x80; if (mode->VScan >= 32) regp->CRTC[9] |= 0x1F; else if (mode->VScan > 1) regp->CRTC[9] |= mode->VScan - 1; regp->CRTC[10] = 0x00; regp->CRTC[11] = 0x00; regp->CRTC[12] = 0x00; regp->CRTC[13] = 0x00; regp->CRTC[14] = 0x00; regp->CRTC[15] = 0x00; regp->CRTC[16] = mode->CrtcVSyncStart & 0xFF; regp->CRTC[17] = (mode->CrtcVSyncEnd & 0x0F) | 0x20; regp->CRTC[18] = (mode->CrtcVDisplay - 1) & 0xFF; regp->CRTC[19] = scrninfp->displayWidth >> 4; /* just a guess */ regp->CRTC[20] = 0x00; regp->CRTC[21] = (mode->CrtcVBlankStart - 1) & 0xFF; regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; if (depth < 8) regp->CRTC[23] = 0xE3; else regp->CRTC[23] = 0xC3; regp->CRTC[24] = 0xFF; vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); /* * Theory resumes here.... */ /* * Graphics Display Controller */ regp->Graphics[0] = 0x00; regp->Graphics[1] = 0x00; regp->Graphics[2] = 0x00; regp->Graphics[3] = 0x00; if (depth == 1) { regp->Graphics[4] = BIT_PLANE; regp->Graphics[5] = 0x00; } else { regp->Graphics[4] = 0x00; if (depth == 4) regp->Graphics[5] = 0x02; else regp->Graphics[5] = 0x40; } regp->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */ regp->Graphics[7] = 0x0F; regp->Graphics[8] = 0xFF; if (depth == 1) { /* Initialise the Mono map according to which bit-plane gets used */ Bool flipPixels = xf86GetFlipPixels(); for (i = 0; i < 16; i++) if (((i & (1 << BIT_PLANE)) != 0) != flipPixels) regp->Attribute[i] = WHITE_VALUE; else regp->Attribute[i] = BLACK_VALUE; regp->Attribute[16] = 0x01; /* -VGA2- *//* wrong for the ET4000 */ if (!hwp->ShowOverscan) regp->Attribute[OVERSCAN] = OVERSCAN_VALUE; /* -VGA2- */ } else { regp->Attribute[0] = 0x00; /* standard colormap translation */ regp->Attribute[1] = 0x01; regp->Attribute[2] = 0x02; regp->Attribute[3] = 0x03; regp->Attribute[4] = 0x04; regp->Attribute[5] = 0x05; regp->Attribute[6] = 0x06; regp->Attribute[7] = 0x07; regp->Attribute[8] = 0x08; regp->Attribute[9] = 0x09; regp->Attribute[10] = 0x0A; regp->Attribute[11] = 0x0B; regp->Attribute[12] = 0x0C; regp->Attribute[13] = 0x0D; regp->Attribute[14] = 0x0E; regp->Attribute[15] = 0x0F; if (depth == 4) regp->Attribute[16] = 0x81; /* wrong for the ET4000 */ else regp->Attribute[16] = 0x41; /* wrong for the ET4000 */ /* Attribute[17] (overscan) initialised in vgaHWGetHWRec() */ } regp->Attribute[18] = 0x0F; regp->Attribute[19] = 0x00; regp->Attribute[20] = 0x00; return TRUE; } /* * OK, so much for theory. Now, let's deal with the >real< world... * * The above CRTC settings are precise in theory, except that many, if not * most, VGA clones fail to reset the blanking signal when the character or * line counter reaches [HV]Total. In this case, the signal is only * unblanked when the counter reaches [HV]BlankEnd (mod 64, 128 or 256 as * the case may be) at the start of the >next< scanline or frame, which * means only part of the screen shows. This affects how null overscans * are to be implemented on such adapters. * * Henceforth, VGA cores that implement this broken, but unfortunately * common, behaviour are to be designated as KGA's, in honour of Koen * Gadeyne, whose zeal to eliminate overscans (read: fury) set in motion * a series of events that led to the discovery of this problem. * * Some VGA's are KGA's only in the horizontal, or only in the vertical, * some in both, others in neither. Don't let anyone tell you there is * such a thing as a VGA "standard"... And, thank the Creator for the fact * that Hilbert spaces are not yet implemented in this industry. * * The following implements a trick suggested by David Dawes. This sets * [HV]BlankEnd to zero if the blanking interval does not already contain a * 0-point, and decrements it by one otherwise. In the latter case, this * will produce a left and/or top overscan which the colourmap code will * (still) need to ensure is as close to black as possible. This will make * the behaviour consistent across all chipsets, while allowing all * chipsets to display the entire screen. Non-KGA drivers can ignore the * following in their own copy of this code. * * -- TSI @ UQV, 1998.08.21 */ CARD32 vgaHWHBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, unsigned int Flags) { int nExtBits = (nBits < 6) ? 0 : nBits - 6; CARD32 ExtBits; CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6; regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) | (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); regp->CRTC[5] = (regp->CRTC[5] & ~0x80) | ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2); ExtBits = ((mode->CrtcHBlankEnd >> 3) - 1) & ExtBitMask; /* First the horizontal case */ if ((Flags & KGA_FIX_OVERSCAN) && ((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3))) { int i = (regp->CRTC[3] & 0x1F) | ((regp->CRTC[5] & 0x80) >> 2) | ExtBits; if (Flags & KGA_ENABLE_ON_ZERO) { if ((i-- > (((mode->CrtcHBlankStart >> 3) - 1) & (0x3F | ExtBitMask))) && (mode->CrtcHBlankEnd == mode->CrtcHTotal)) i = 0; } else if (Flags & KGA_BE_TOT_DEC) i--; regp->CRTC[3] = (regp->CRTC[3] & ~0x1F) | (i & 0x1F); regp->CRTC[5] = (regp->CRTC[5] & ~0x80) | ((i << 2) & 0x80); ExtBits = i & ExtBitMask; } return ExtBits >> 6; } /* * The vertical case is a little trickier. Some VGA's ignore bit 0x80 of * CRTC[22]. Also, in some cases, a zero CRTC[22] will still blank the * very first scanline in a double- or multi-scanned mode. This last case * needs further investigation. */ CARD32 vgaHWVBlankKGA(DisplayModePtr mode, vgaRegPtr regp, int nBits, unsigned int Flags) { CARD32 ExtBits; CARD32 nExtBits = (nBits < 8) ? 0 : (nBits - 8); CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 8; /* If width is not known nBits should be 0. In this * case BitMask is set to 0 so we can check for it. */ CARD32 BitMask = (nBits < 7) ? 0 : ((1 << nExtBits) - 1); int VBlankStart = (mode->CrtcVBlankStart - 1) & 0xFF; regp->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; ExtBits = (mode->CrtcVBlankEnd - 1) & ExtBitMask; if ((Flags & KGA_FIX_OVERSCAN) && (mode->CrtcVBlankEnd == mode->CrtcVTotal)) /* Null top overscan */ { int i = regp->CRTC[22] | ExtBits; if (Flags & KGA_ENABLE_ON_ZERO) { if (((BitMask && ((i & BitMask) > (VBlankStart & BitMask))) || ((i > VBlankStart) && /* 8-bit case */ ((i & 0x7F) > (VBlankStart & 0x7F)))) && /* 7-bit case */ !(regp->CRTC[9] & 0x9F)) /* 1 scanline/row */ i = 0; else i = (i - 1); } else if (Flags & KGA_BE_TOT_DEC) i = (i - 1); regp->CRTC[22] = i & 0xFF; ExtBits = i & 0xFF00; } return ExtBits >> 8; } /* * these are some more hardware specific helpers, formerly in vga.c */ static void vgaHWGetHWRecPrivate(void) { if (vgaHWPrivateIndex < 0) vgaHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); return; } static void vgaHWFreeRegs(vgaRegPtr regp) { free(regp->CRTC); regp->CRTC = regp->Sequencer = regp->Graphics = regp->Attribute = NULL; regp->numCRTC = regp->numSequencer = regp->numGraphics = regp->numAttribute = 0; } static Bool vgaHWAllocRegs(vgaRegPtr regp) { unsigned char *buf; if ((regp->numCRTC + regp->numSequencer + regp->numGraphics + regp->numAttribute) == 0) return FALSE; buf = calloc(regp->numCRTC + regp->numSequencer + regp->numGraphics + regp->numAttribute, 1); if (!buf) return FALSE; regp->CRTC = buf; regp->Sequencer = regp->CRTC + regp->numCRTC; regp->Graphics = regp->Sequencer + regp->numSequencer; regp->Attribute = regp->Graphics + regp->numGraphics; return TRUE; } Bool vgaHWAllocDefaultRegs(vgaRegPtr regp) { regp->numCRTC = VGA_NUM_CRTC; regp->numSequencer = VGA_NUM_SEQ; regp->numGraphics = VGA_NUM_GFX; regp->numAttribute = VGA_NUM_ATTR; return vgaHWAllocRegs(regp); } Bool vgaHWSetRegCounts(ScrnInfoPtr scrp, int numCRTC, int numSequencer, int numGraphics, int numAttribute) { #define VGAHWMINNUM(regtype) \ ((newMode.num##regtype < regp->num##regtype) ? \ (newMode.num##regtype) : (regp->num##regtype)) #define VGAHWCOPYREGSET(regtype) \ memcpy (newMode.regtype, regp->regtype, VGAHWMINNUM(regtype)) vgaRegRec newMode, newSaved; vgaRegPtr regp; regp = &VGAHWPTR(scrp)->ModeReg; memcpy(&newMode, regp, sizeof(vgaRegRec)); /* allocate space for new registers */ regp = &newMode; regp->numCRTC = numCRTC; regp->numSequencer = numSequencer; regp->numGraphics = numGraphics; regp->numAttribute = numAttribute; if (!vgaHWAllocRegs(regp)) return FALSE; regp = &VGAHWPTR(scrp)->SavedReg; memcpy(&newSaved, regp, sizeof(vgaRegRec)); regp = &newSaved; regp->numCRTC = numCRTC; regp->numSequencer = numSequencer; regp->numGraphics = numGraphics; regp->numAttribute = numAttribute; if (!vgaHWAllocRegs(regp)) { vgaHWFreeRegs(&newMode); return FALSE; } /* allocations succeeded, copy register data into new space */ regp = &VGAHWPTR(scrp)->ModeReg; VGAHWCOPYREGSET(CRTC); VGAHWCOPYREGSET(Sequencer); VGAHWCOPYREGSET(Graphics); VGAHWCOPYREGSET(Attribute); regp = &VGAHWPTR(scrp)->SavedReg; VGAHWCOPYREGSET(CRTC); VGAHWCOPYREGSET(Sequencer); VGAHWCOPYREGSET(Graphics); VGAHWCOPYREGSET(Attribute); /* free old register arrays */ regp = &VGAHWPTR(scrp)->ModeReg; vgaHWFreeRegs(regp); memcpy(regp, &newMode, sizeof(vgaRegRec)); regp = &VGAHWPTR(scrp)->SavedReg; vgaHWFreeRegs(regp); memcpy(regp, &newSaved, sizeof(vgaRegRec)); return TRUE; #undef VGAHWMINNUM #undef VGAHWCOPYREGSET } Bool vgaHWCopyReg(vgaRegPtr dst, vgaRegPtr src) { vgaHWFreeRegs(dst); memcpy(dst, src, sizeof(vgaRegRec)); if (!vgaHWAllocRegs(dst)) return FALSE; memcpy(dst->CRTC, src->CRTC, src->numCRTC); memcpy(dst->Sequencer, src->Sequencer, src->numSequencer); memcpy(dst->Graphics, src->Graphics, src->numGraphics); memcpy(dst->Attribute, src->Attribute, src->numAttribute); return TRUE; } Bool vgaHWGetHWRec(ScrnInfoPtr scrp) { vgaRegPtr regp; vgaHWPtr hwp; int i; /* * Let's make sure that the private exists and allocate one. */ vgaHWGetHWRecPrivate(); /* * New privates are always set to NULL, so we can check if the allocation * has already been done. */ if (VGAHWPTR(scrp)) return TRUE; hwp = VGAHWPTRLVAL(scrp) = xnfcalloc(sizeof(vgaHWRec), 1); regp = &VGAHWPTR(scrp)->ModeReg; if ((!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->SavedReg)) || (!vgaHWAllocDefaultRegs(&VGAHWPTR(scrp)->ModeReg))) { free(hwp); return FALSE; } if (scrp->bitsPerPixel == 1) { rgb blackColour = scrp->display->blackColour, whiteColour = scrp->display->whiteColour; if (blackColour.red > 0x3F) blackColour.red = 0x3F; if (blackColour.green > 0x3F) blackColour.green = 0x3F; if (blackColour.blue > 0x3F) blackColour.blue = 0x3F; if (whiteColour.red > 0x3F) whiteColour.red = 0x3F; if (whiteColour.green > 0x3F) whiteColour.green = 0x3F; if (whiteColour.blue > 0x3F) whiteColour.blue = 0x3F; if ((blackColour.red == whiteColour.red) && (blackColour.green == whiteColour.green) && (blackColour.blue == whiteColour.blue)) { blackColour.red ^= 0x3F; blackColour.green ^= 0x3F; blackColour.blue ^= 0x3F; } /* * initialize default colormap for monochrome */ for (i = 0; i < 3; i++) regp->DAC[i] = 0x00; for (i = 3; i < 768; i++) regp->DAC[i] = 0x3F; i = BLACK_VALUE * 3; regp->DAC[i++] = blackColour.red; regp->DAC[i++] = blackColour.green; regp->DAC[i] = blackColour.blue; i = WHITE_VALUE * 3; regp->DAC[i++] = whiteColour.red; regp->DAC[i++] = whiteColour.green; regp->DAC[i] = whiteColour.blue; i = OVERSCAN_VALUE * 3; regp->DAC[i++] = 0x00; regp->DAC[i++] = 0x00; regp->DAC[i] = 0x00; } else { /* Set all colours to black */ for (i = 0; i < 768; i++) regp->DAC[i] = 0x00; /* ... and the overscan */ if (scrp->depth >= 4) regp->Attribute[OVERSCAN] = 0xFF; } if (xf86FindOption(scrp->confScreen->options, "ShowOverscan")) { xf86MarkOptionUsedByName(scrp->confScreen->options, "ShowOverscan"); xf86DrvMsg(scrp->scrnIndex, X_CONFIG, "Showing overscan area\n"); regp->DAC[765] = 0x3F; regp->DAC[766] = 0x00; regp->DAC[767] = 0x3F; regp->Attribute[OVERSCAN] = 0xFF; hwp->ShowOverscan = TRUE; } else hwp->ShowOverscan = FALSE; hwp->paletteEnabled = FALSE; hwp->cmapSaved = FALSE; hwp->MapSize = 0; hwp->pScrn = scrp; hwp->dev = xf86GetPciInfoForEntity(scrp->entityList[0]); return TRUE; } void vgaHWFreeHWRec(ScrnInfoPtr scrp) { if (vgaHWPrivateIndex >= 0) { vgaHWPtr hwp = VGAHWPTR(scrp); if (!hwp) return; pci_device_close_io(hwp->dev, hwp->io); free(hwp->FontInfo1); free(hwp->FontInfo2); free(hwp->TextInfo); vgaHWFreeRegs(&hwp->ModeReg); vgaHWFreeRegs(&hwp->SavedReg); free(hwp); VGAHWPTRLVAL(scrp) = NULL; } } Bool vgaHWMapMem(ScrnInfoPtr scrp) { vgaHWPtr hwp = VGAHWPTR(scrp); if (hwp->Base) return TRUE; /* If not set, initialise with the defaults */ if (hwp->MapSize == 0) hwp->MapSize = VGA_DEFAULT_MEM_SIZE; if (hwp->MapPhys == 0) hwp->MapPhys = VGA_DEFAULT_PHYS_ADDR; /* * Map as VIDMEM_MMIO_32BIT because WC * is bad when there is page flipping. * XXX This is not correct but we do it * for now. */ DebugF("Mapping VGAMem\n"); pci_device_map_legacy(hwp->dev, hwp->MapPhys, hwp->MapSize, PCI_DEV_MAP_FLAG_WRITABLE, &hwp->Base); return hwp->Base != NULL; } void vgaHWUnmapMem(ScrnInfoPtr scrp) { vgaHWPtr hwp = VGAHWPTR(scrp); if (hwp->Base == NULL) return; DebugF("Unmapping VGAMem\n"); pci_device_unmap_legacy(hwp->dev, hwp->Base, hwp->MapSize); hwp->Base = NULL; } int vgaHWGetIndex(void) { return vgaHWPrivateIndex; } void vgaHWGetIOBase(vgaHWPtr hwp) { hwp->IOBase = (hwp->readMiscOut(hwp) & 0x01) ? VGA_IOBASE_COLOR : VGA_IOBASE_MONO; xf86DrvMsgVerb(hwp->pScrn->scrnIndex, X_INFO, 3, "vgaHWGetIOBase: hwp->IOBase is 0x%04x\n", hwp->IOBase); } void vgaHWLock(vgaHWPtr hwp) { /* Protect CRTC[0-7] */ hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) | 0x80); } void vgaHWUnlock(vgaHWPtr hwp) { /* Unprotect CRTC[0-7] */ hwp->writeCrtc(hwp, 0x11, hwp->readCrtc(hwp, 0x11) & ~0x80); } void vgaHWEnable(vgaHWPtr hwp) { hwp->writeEnable(hwp, hwp->readEnable(hwp) | 0x01); } void vgaHWDisable(vgaHWPtr hwp) { hwp->writeEnable(hwp, hwp->readEnable(hwp) & ~0x01); } static void vgaHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) { vgaHWPtr hwp = VGAHWPTR(pScrn); int i, index; for (i = 0; i < numColors; i++) { index = indices[i]; hwp->writeDacWriteAddr(hwp, index); DACDelay(hwp); hwp->writeDacData(hwp, colors[index].red); DACDelay(hwp); hwp->writeDacData(hwp, colors[index].green); DACDelay(hwp); hwp->writeDacData(hwp, colors[index].blue); DACDelay(hwp); } /* This shouldn't be necessary, but we'll play safe. */ hwp->disablePalette(hwp); } static void vgaHWSetOverscan(ScrnInfoPtr pScrn, int overscan) { vgaHWPtr hwp = VGAHWPTR(pScrn); if (overscan < 0 || overscan > 255) return; hwp->enablePalette(hwp); hwp->writeAttr(hwp, OVERSCAN, overscan); #ifdef DEBUGOVERSCAN { int ov = hwp->readAttr(hwp, OVERSCAN); int red, green, blue; hwp->writeDacReadAddr(hwp, ov); red = hwp->readDacData(hwp); green = hwp->readDacData(hwp); blue = hwp->readDacData(hwp); ErrorF("Overscan index is 0x%02x, colours are #%02x%02x%02x\n", ov, red, green, blue); } #endif hwp->disablePalette(hwp); } Bool vgaHWHandleColormaps(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; if (pScrn->depth > 1 && pScrn->depth <= 8) { return xf86HandleColormaps(pScreen, 1 << pScrn->depth, pScrn->rgbBits, vgaHWLoadPalette, pScrn->depth > 4 ? vgaHWSetOverscan : NULL, CMAP_RELOAD_ON_MODE_SWITCH); } return TRUE; } /* ----------------------- DDC support ------------------------*/ /* * Adjust v_active, v_blank, v_sync, v_sync_end, v_blank_end, v_total * to read out EDID at a faster rate. Allowed maximum is 25kHz with * 20 usec v_sync active. Set positive v_sync polarity, turn off lightpen * readback, enable access to cr00-cr07. */ /* vertical timings */ #define DISPLAY_END 0x04 #define BLANK_START DISPLAY_END #define SYNC_START BLANK_START #define SYNC_END 0x09 #define BLANK_END SYNC_END #define V_TOTAL BLANK_END /* this function doesn't have to be reentrant for our purposes */ struct _vgaDdcSave { unsigned char cr03; unsigned char cr06; unsigned char cr07; unsigned char cr09; unsigned char cr10; unsigned char cr11; unsigned char cr12; unsigned char cr15; unsigned char cr16; unsigned char msr; }; void vgaHWddc1SetSpeed(ScrnInfoPtr pScrn, xf86ddcSpeed speed) { vgaHWPtr hwp = VGAHWPTR(pScrn); unsigned char tmp; struct _vgaDdcSave *save; switch (speed) { case DDC_FAST: if (hwp->ddc != NULL) break; hwp->ddc = xnfcalloc(sizeof(struct _vgaDdcSave), 1); save = (struct _vgaDdcSave *) hwp->ddc; /* Lightpen register disable - allow access to cr10 & 11; just in case */ save->cr03 = hwp->readCrtc(hwp, 0x03); hwp->writeCrtc(hwp, 0x03, (save->cr03 | 0x80)); save->cr12 = hwp->readCrtc(hwp, 0x12); hwp->writeCrtc(hwp, 0x12, DISPLAY_END); save->cr15 = hwp->readCrtc(hwp, 0x15); hwp->writeCrtc(hwp, 0x15, BLANK_START); save->cr10 = hwp->readCrtc(hwp, 0x10); hwp->writeCrtc(hwp, 0x10, SYNC_START); save->cr11 = hwp->readCrtc(hwp, 0x11); /* unprotect group 1 registers; just in case ... */ hwp->writeCrtc(hwp, 0x11, ((save->cr11 & 0x70) | SYNC_END)); save->cr16 = hwp->readCrtc(hwp, 0x16); hwp->writeCrtc(hwp, 0x16, BLANK_END); save->cr06 = hwp->readCrtc(hwp, 0x06); hwp->writeCrtc(hwp, 0x06, V_TOTAL); /* all values have less than 8 bit - mask out 9th and 10th bits */ save->cr09 = hwp->readCrtc(hwp, 0x09); hwp->writeCrtc(hwp, 0x09, (save->cr09 & 0xDF)); save->cr07 = hwp->readCrtc(hwp, 0x07); hwp->writeCrtc(hwp, 0x07, (save->cr07 & 0x10)); /* vsync polarity negativ & ensure a 25MHz clock */ save->msr = hwp->readMiscOut(hwp); hwp->writeMiscOut(hwp, ((save->msr & 0xF3) | 0x80)); break; case DDC_SLOW: if (hwp->ddc == NULL) break; save = (struct _vgaDdcSave *) hwp->ddc; hwp->writeMiscOut(hwp, save->msr); hwp->writeCrtc(hwp, 0x07, save->cr07); tmp = hwp->readCrtc(hwp, 0x09); hwp->writeCrtc(hwp, 0x09, ((save->cr09 & 0x20) | (tmp & 0xDF))); hwp->writeCrtc(hwp, 0x06, save->cr06); hwp->writeCrtc(hwp, 0x16, save->cr16); hwp->writeCrtc(hwp, 0x11, save->cr11); hwp->writeCrtc(hwp, 0x10, save->cr10); hwp->writeCrtc(hwp, 0x15, save->cr15); hwp->writeCrtc(hwp, 0x12, save->cr12); hwp->writeCrtc(hwp, 0x03, save->cr03); free(save); hwp->ddc = NULL; break; default: break; } } DDC1SetSpeedProc vgaHWddc1SetSpeedWeak(void) { return vgaHWddc1SetSpeed; } SaveScreenProcPtr vgaHWSaveScreenWeak(void) { return vgaHWSaveScreen; } /* * xf86GetClocks -- get the dot-clocks via a BIG BAD hack ... */ void xf86GetClocks(ScrnInfoPtr pScrn, int num, Bool (*ClockFunc) (ScrnInfoPtr, int), void (*ProtectRegs) (ScrnInfoPtr, Bool), void (*BlankScreen) (ScrnInfoPtr, Bool), unsigned long vertsyncreg, int maskval, int knownclkindex, int knownclkvalue) { register int status = vertsyncreg; unsigned long i, cnt, rcnt, sync; vgaHWPtr hwp = VGAHWPTR(pScrn); /* First save registers that get written on */ (*ClockFunc) (pScrn, CLK_REG_SAVE); if (num > MAXCLOCKS) num = MAXCLOCKS; for (i = 0; i < num; i++) { if (ProtectRegs) (*ProtectRegs) (pScrn, TRUE); if (!(*ClockFunc) (pScrn, i)) { pScrn->clock[i] = -1; continue; } if (ProtectRegs) (*ProtectRegs) (pScrn, FALSE); if (BlankScreen) (*BlankScreen) (pScrn, FALSE); usleep(50000); /* let VCO stabilise */ cnt = 0; sync = 200000; while ((pci_io_read8(hwp->io, status) & maskval) == 0x00) if (sync-- == 0) goto finish; /* Something appears to be happening, so reset sync count */ sync = 200000; while ((pci_io_read8(hwp->io, status) & maskval) == maskval) if (sync-- == 0) goto finish; /* Something appears to be happening, so reset sync count */ sync = 200000; while ((pci_io_read8(hwp->io, status) & maskval) == 0x00) if (sync-- == 0) goto finish; for (rcnt = 0; rcnt < 5; rcnt++) { while (!(pci_io_read8(hwp->io, status) & maskval)) cnt++; while ((pci_io_read8(hwp->io, status) & maskval)) cnt++; } finish: pScrn->clock[i] = cnt ? cnt : -1; if (BlankScreen) (*BlankScreen) (pScrn, TRUE); } for (i = 0; i < num; i++) { if (i != knownclkindex) { if (pScrn->clock[i] == -1) { pScrn->clock[i] = 0; } else { pScrn->clock[i] = (int) (0.5 + (((float) knownclkvalue) * pScrn->clock[knownclkindex]) / (pScrn->clock[i])); /* Round to nearest 10KHz */ pScrn->clock[i] += 5; pScrn->clock[i] /= 10; pScrn->clock[i] *= 10; } } } pScrn->clock[knownclkindex] = knownclkvalue; pScrn->numClocks = num; /* Restore registers that were written on */ (*ClockFunc) (pScrn, CLK_REG_RESTORE); }