/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_dga.c,v 1.9 2001/01/06 21:29:11 tsi Exp $ */ /* * file: apm_dga.c * ported from s3virge, ported from mga * */ #include "xf86.h" #include "xf86_OSproc.h" #include "xf86_ansic.h" #include "xf86Pci.h" #include "xf86PciInfo.h" #include "xaa.h" #include "xaalocal.h" #include "apm.h" #include "dgaproc.h" static Bool ApmOpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, int *, int *, int *); static Bool ApmSetMode(ScrnInfoPtr, DGAModePtr); static int ApmGetViewport(ScrnInfoPtr); static void ApmSetViewport(ScrnInfoPtr, int, int, int); static void ApmFillRect(ScrnInfoPtr, int, int, int, int, unsigned long); static void ApmBlitRect(ScrnInfoPtr, int, int, int, int, int, int); static void ApmBlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, unsigned long); static void ApmSync(ScrnInfoPtr); static DGAFunctionRec ApmDGAFuncs = { ApmOpenFramebuffer, NULL, ApmSetMode, ApmSetViewport, ApmGetViewport, ApmSync, ApmFillRect, ApmBlitRect, ApmBlitTransRect }; /* * Placeholder */ void ApmSync(ScrnInfoPtr pScrn) { } static __inline__ int FindSmallestPitch(ApmPtr pApm, int Bpp, int width) { if (width <= 640) return 640; else if (width <= 800) return 800; else if (width <= 1024) return 1024; else if (width <= 1152) return 1152; else if (width <= 1280) return 1280; else if (width <= 1600) return 1600; return (width + 7) & ~7; } static DGAModePtr ApmSetupDGAMode(ScrnInfoPtr pScrn, DGAModePtr modes, int *num, int bitsPerPixel, int depth, Bool pixmap, int secondPitch, unsigned long red, unsigned long green, unsigned long blue, short visualClass) { DisplayModePtr firstMode, pMode; APMDECL(pScrn); DGAModePtr mode, newmodes; int size, pitch, Bpp = bitsPerPixel >> 3; Bool reduced_pitch = TRUE; SECOND_PASS: firstMode = NULL; for (pMode = pScrn->modes; pMode != firstMode; pMode = pMode->next) { if (!firstMode) firstMode = pMode; if (reduced_pitch) pitch = FindSmallestPitch(pApm, Bpp, pMode->HDisplay); else pitch = pMode->HDisplay; if (!reduced_pitch && pitch == FindSmallestPitch(pApm, Bpp, pMode->HDisplay)) continue; size = pitch * Bpp * pMode->VDisplay; if((!secondPitch || (pitch != secondPitch)) && (size <= pScrn->videoRam * 1024 - pApm->OffscreenReserved)) { if(secondPitch) pitch = secondPitch; if(!(newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec)))) break; modes = newmodes; mode = modes + *num; mode->mode = pMode; mode->flags = DGA_CONCURRENT_ACCESS; if(pixmap) mode->flags |= DGA_PIXMAP_AVAILABLE; if(!pApm->NoAccel) { mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; if (Bpp != 3) mode->flags |= DGA_BLIT_RECT_TRANS; } if(pMode->Flags & V_DBLSCAN) mode->flags |= DGA_DOUBLESCAN; if(pMode->Flags & V_INTERLACE) mode->flags |= DGA_INTERLACED; mode->byteOrder = pScrn->imageByteOrder; mode->depth = depth; mode->bitsPerPixel = bitsPerPixel; mode->red_mask = red; mode->green_mask = green; mode->blue_mask = blue; mode->visualClass = visualClass; mode->viewportWidth = pMode->HDisplay; mode->viewportHeight = pMode->VDisplay; mode->xViewportStep = (bitsPerPixel == 24) ? 4 : 1; mode->yViewportStep = 1; mode->viewportFlags = DGA_FLIP_RETRACE; mode->offset = 0; mode->address = pApm->FbBase; mode->bytesPerScanline = pitch * Bpp; mode->imageWidth = pitch; mode->imageHeight = (pScrn->videoRam * 1024 - pApm->OffscreenReserved) / mode->bytesPerScanline; mode->pixmapWidth = mode->imageWidth; mode->pixmapHeight = mode->imageHeight; mode->maxViewportX = mode->imageWidth - mode->viewportWidth; /* this might need to get clamped to some maximum */ mode->maxViewportY = mode->imageHeight - mode->viewportHeight; (*num)++; } } if(secondPitch) { secondPitch = 0; goto SECOND_PASS; } if (reduced_pitch) { reduced_pitch = FALSE; goto SECOND_PASS; } return modes; } Bool ApmDGAInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; APMDECL(pScrn); DGAModePtr modes = NULL; int num = 0; /* 8 */ modes = ApmSetupDGAMode (pScrn, modes, &num, 8, 8, (pScrn->bitsPerPixel != 24), (pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth, 0, 0, 0, PseudoColor); /* 15 */ modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 15, (pScrn->bitsPerPixel != 24), (pScrn->depth != 15) ? 0 : pScrn->displayWidth, 0x7C00, 0x03E0, 0x001F, TrueColor); modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 15, (pScrn->bitsPerPixel != 24), (pScrn->depth != 15) ? 0 : pScrn->displayWidth, 0x7C00, 0x03E0, 0x001F, DirectColor); /* 16 */ modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 16, (pScrn->bitsPerPixel != 24), (pScrn->depth != 16) ? 0 : pScrn->displayWidth, 0xF800, 0x07E0, 0x001F, TrueColor); modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 16, (pScrn->bitsPerPixel != 24), (pScrn->depth != 16) ? 0 : pScrn->displayWidth, 0xF800, 0x07E0, 0x001F, DirectColor); /* 24 */ modes = ApmSetupDGAMode (pScrn, modes, &num, 24, 24, (pScrn->bitsPerPixel == 24), (pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth, 0xFF0000, 0x00FF00, 0x0000FF, TrueColor); modes = ApmSetupDGAMode (pScrn, modes, &num, 24, 24, (pScrn->bitsPerPixel == 24), (pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth, 0xFF0000, 0x00FF00, 0x0000FF, DirectColor); /* 32 */ modes = ApmSetupDGAMode (pScrn, modes, &num, 32, 24, (pScrn->bitsPerPixel != 24), (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth, 0xFF0000, 0x00FF00, 0x0000FF, TrueColor); modes = ApmSetupDGAMode (pScrn, modes, &num, 32, 24, (pScrn->bitsPerPixel != 24), (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth, 0xFF0000, 0x00FF00, 0x0000FF, DirectColor); pApm->numDGAModes = num; pApm->DGAModes = modes; return DGAInit(pScreen, &ApmDGAFuncs, modes, num); } static Bool ApmSetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) { int index = pScrn->pScreen->myNum; APMDECL(pScrn); if (!pMode) { /* restore the original mode */ if (pApm->DGAactive) { memcpy(&pApm->CurrentLayout, &pApm->SavedLayout, sizeof pApm->CurrentLayout); pApm->DGAactive = FALSE; } pScrn->currentMode = pApm->CurrentLayout.pMode; ApmSwitchMode(index, pScrn->currentMode, 0); ApmAdjustFrame(index, pScrn->frameX0, pScrn->frameY0, 0); #if 0 if (pApm->AccelInfoRec) XAAInit(pScrn->pScreen, pApm->AccelInfoRec); #endif } else { if (!pApm->DGAactive) { memcpy(&pApm->SavedLayout, &pApm->CurrentLayout, sizeof pApm->CurrentLayout); pApm->DGAactive = TRUE; } pApm->CurrentLayout.displayWidth = pMode->imageWidth; pApm->CurrentLayout.displayHeight = pMode->imageHeight; pApm->CurrentLayout.Scanlines = pMode->imageHeight + 1; pApm->CurrentLayout.depth = pMode->depth; pApm->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel; pApm->CurrentLayout.bytesPerScanline = pMode->bytesPerScanline; pApm->CurrentLayout.pMode = pMode->mode; if (pMode->bitsPerPixel == 24) pApm->CurrentLayout.mask32 = 3; else pApm->CurrentLayout.mask32 = 32 / pMode->bitsPerPixel - 1; ApmSwitchMode(index, pMode->mode, 0); ApmSetupXAAInfo(pApm, NULL); #if 0 if (pApm->DGAXAAInfo) bzero(pApm->DGAXAAInfo, sizeof(*pApm->DGAXAAInfo)); else pApm->DGAXAAInfo = XAACreateInfoRec(); ApmSetupXAAInfo(pApm, pApm->DGAXAAInfo); /* * Let's hope this won't fail, that is reinitialize XAA for this * setup... */ XAAInit(pScrn->pScreen, pApm->DGAXAAInfo); #endif } return TRUE; } static int ApmGetViewport( ScrnInfoPtr pScrn ) { return 0; } static void ApmSetViewport( ScrnInfoPtr pScrn, int x, int y, int flags ) { unsigned char tmp; APMDECL(pScrn); if (pApm->apmLock) { /* * This is just an attempt, because Daryll is tampering with MY * registers. */ if (!pApm->noLinear) { tmp = (RDXB(0xDB) & 0xF4) | 0x0A; WRXB(0xDB, tmp); ApmWriteSeq(0x1B, 0x20); ApmWriteSeq(0x1C, 0x2F); } else { tmp = (RDXB_IOP(0xDB) & 0xF4) | 0x0A; WRXB_IOP(0xDB, tmp); wrinx(pApm->xport, 0x1B, 0x20); wrinx(pApm->xport, 0x1C, 0x2F); } pApm->apmLock = FALSE; } pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags); if (pApm->VGAMap) { /* Wait until vertical retrace is in progress. */ while (APMVGAB(0x3DA) & 0x08); while (!(APMVGAB(0x3DA) & 0x08)); } else { /* Wait until vertical retrace is in progress. */ while (inb(pApm->iobase + 0x3DA) & 0x08); while (!(inb(pApm->iobase + 0x3DA) & 0x08)); } } static void ApmFillRect ( ScrnInfoPtr pScrn, int x, int y, int w, int h, unsigned long color ) { APMDECL(pScrn); if(pApm->CurrentLayout.depth != 24) { (*pApm->SetupForSolidFill)(pScrn, color, GXcopy, ~0); (*pApm->SubsequentSolidFillRect)(pScrn, x, y, w, h); } else { (*pApm->SetupForSolidFill24)(pScrn, color, GXcopy, ~0); (*pApm->SubsequentSolidFillRect24)(pScrn, x, y, w, h); } SET_SYNC_FLAG(pApm->AccelInfoRec); } static void ApmBlitRect( ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h, int dstx, int dsty ) { APMDECL(pScrn); int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; int ydir = (srcy < dsty) ? -1 : 1; if(pApm->CurrentLayout.depth != 24) { (*pApm->SetupForScreenToScreenCopy)( pScrn, xdir, ydir, GXcopy, ~0, -1); (*pApm->SubsequentScreenToScreenCopy)( pScrn, srcx, srcy, dstx, dsty, w, h); } else { (*pApm->SetupForScreenToScreenCopy24)( pScrn, xdir, ydir, GXcopy, ~0, -1); (*pApm->SubsequentScreenToScreenCopy24)( pScrn, srcx, srcy, dstx, dsty, w, h); } SET_SYNC_FLAG(pApm->AccelInfoRec); } static void ApmBlitTransRect( ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long color ) { APMDECL(pScrn); if(pApm->AccelInfoRec) { int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; int ydir = (srcy < dsty) ? -1 : 1; (*pApm->AccelInfoRec->SetupForScreenToScreenCopy)( pScrn, xdir, ydir, GXcopy, ~0, (int)color); (*pApm->AccelInfoRec->SubsequentScreenToScreenCopy)( pScrn, srcx, srcy, dstx, dsty, w, h); SET_SYNC_FLAG(pApm->AccelInfoRec); } } static Bool ApmOpenFramebuffer( ScrnInfoPtr pScrn, char **name, unsigned char **mem, int *size, int *offset, int *flags ) { APMDECL(pScrn); *name = NULL; /* no special device */ *mem = (unsigned char*)(pApm->LinAddress + 0*((char *)pApm->FbBase - (char *)pApm->LinMap)); *size = pScrn->videoRam << 10; *offset = 0; *flags = DGA_NEED_ROOT; return TRUE; }