462 lines
12 KiB
C
462 lines
12 KiB
C
/*
|
|
* Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of Marc Aurele La France not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. Marc Aurele La France makes no representations
|
|
* about the suitability of this software for any purpose. It is provided
|
|
* "as-is" without express or implied warranty.
|
|
*
|
|
* MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
* EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include "ati.h"
|
|
#include "atidac.h"
|
|
#include "atimach64io.h"
|
|
|
|
/*
|
|
* RAMDAC-related definitions.
|
|
*/
|
|
const SymTabRec ATIDACDescriptors[] =
|
|
{ /* Keep this table in ascending DACType order */
|
|
{ATI_DAC_ATI68830, "ATI 68830 or similar"},
|
|
{ATI_DAC_SC11483, "Sierra 11483 or similar"},
|
|
{ATI_DAC_ATI68875, "ATI 68875 or similar"},
|
|
{ATI_DAC_TVP3026_A, "TI ViewPoint3026 or similar"},
|
|
{ATI_DAC_GENERIC, "Brooktree 476 or similar"},
|
|
{ATI_DAC_BT481, "Brooktree 481 or similar"},
|
|
{ATI_DAC_ATT20C491, "AT&T 20C491 or similar"},
|
|
{ATI_DAC_SC15026, "Sierra 15026 or similar"},
|
|
{ATI_DAC_MU9C1880, "Music 9C1880 or similar"},
|
|
{ATI_DAC_IMSG174, "Inmos G174 or similar"},
|
|
{ATI_DAC_ATI68860_B, "ATI 68860 (Revision B) or similar"},
|
|
{ATI_DAC_ATI68860_C, "ATI 68860 (Revision C) or similar"},
|
|
{ATI_DAC_TVP3026_B, "TI ViewPoint3026 or similar"},
|
|
{ATI_DAC_STG1700, "SGS-Thompson 1700 or similar"},
|
|
{ATI_DAC_ATT20C498, "AT&T 20C498 or similar"},
|
|
{ATI_DAC_STG1702, "SGS-Thompson 1702 or similar"},
|
|
{ATI_DAC_SC15021, "Sierra 15021 or similar"},
|
|
{ATI_DAC_ATT21C498, "AT&T 21C498 or similar"},
|
|
{ATI_DAC_STG1703, "SGS-Thompson 1703 or similar"},
|
|
{ATI_DAC_CH8398, "Chrontel 8398 or similar"},
|
|
{ATI_DAC_ATT20C408, "AT&T 20C408 or similar"},
|
|
{ATI_DAC_INTERNAL, "Internal"},
|
|
{ATI_DAC_IBMRGB514, "IBM RGB 514 or similar"},
|
|
{ATI_DAC_UNKNOWN, "Unknown"} /* Must be last */
|
|
};
|
|
|
|
#ifndef AVOID_CPIO
|
|
|
|
/*
|
|
* ATISetDACIOPorts --
|
|
*
|
|
* This function sets up DAC access I/O port numbers.
|
|
*/
|
|
void
|
|
ATISetDACIOPorts
|
|
(
|
|
ATIPtr pATI,
|
|
ATICRTCType crtc
|
|
)
|
|
{
|
|
switch (crtc)
|
|
{
|
|
case ATI_CRTC_VGA:
|
|
pATI->CPIO_DAC_DATA = VGA_DAC_DATA;
|
|
pATI->CPIO_DAC_MASK = VGA_DAC_MASK;
|
|
pATI->CPIO_DAC_READ = VGA_DAC_READ;
|
|
pATI->CPIO_DAC_WRITE = VGA_DAC_WRITE;
|
|
pATI->CPIO_DAC_WAIT = GENS1(pATI->CPIO_VGABase);
|
|
break;
|
|
|
|
case ATI_CRTC_8514:
|
|
pATI->CPIO_DAC_DATA = IBM_DAC_DATA;
|
|
pATI->CPIO_DAC_MASK = IBM_DAC_MASK;
|
|
pATI->CPIO_DAC_READ = IBM_DAC_READ;
|
|
pATI->CPIO_DAC_WRITE = IBM_DAC_WRITE;
|
|
pATI->CPIO_DAC_WAIT = pATI->CPIO_DAC_MASK;
|
|
break;
|
|
|
|
case ATI_CRTC_MACH64:
|
|
pATI->CPIO_DAC_DATA = ATIIOPort(DAC_REGS) + 1;
|
|
pATI->CPIO_DAC_MASK = ATIIOPort(DAC_REGS) + 2;
|
|
pATI->CPIO_DAC_READ = ATIIOPort(DAC_REGS) + 3;
|
|
pATI->CPIO_DAC_WRITE = ATIIOPort(DAC_REGS) + 0;
|
|
pATI->CPIO_DAC_WAIT = pATI->CPIOBase;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif /* AVOID_CPIO */
|
|
|
|
/*
|
|
* ATIGetDACCmdReg --
|
|
*
|
|
* Setup to access a RAMDAC's command register.
|
|
*/
|
|
CARD8
|
|
ATIGetDACCmdReg
|
|
(
|
|
ATIPtr pATI
|
|
)
|
|
{
|
|
|
|
#ifdef AVOID_CPIO
|
|
|
|
(void)in8(M64_DAC_WRITE); /* Reset to PEL mode */
|
|
(void)in8(M64_DAC_MASK);
|
|
(void)in8(M64_DAC_MASK);
|
|
(void)in8(M64_DAC_MASK);
|
|
return in8(M64_DAC_MASK);
|
|
|
|
#else /* AVOID_CPIO */
|
|
|
|
(void)inb(pATI->CPIO_DAC_WRITE); /* Reset to PEL mode */
|
|
(void)inb(pATI->CPIO_DAC_MASK);
|
|
(void)inb(pATI->CPIO_DAC_MASK);
|
|
(void)inb(pATI->CPIO_DAC_MASK);
|
|
return inb(pATI->CPIO_DAC_MASK);
|
|
|
|
#endif /* AVOID_CPIO */
|
|
|
|
}
|
|
|
|
/*
|
|
* ATIDACPreInit --
|
|
*
|
|
* This function initialises the fields in an ATIHWRec that relate to DACs.
|
|
*/
|
|
void
|
|
ATIDACPreInit
|
|
(
|
|
ScrnInfoPtr pScreenInfo,
|
|
ATIPtr pATI,
|
|
ATIHWPtr pATIHW
|
|
)
|
|
{
|
|
int Index, Index2;
|
|
CARD8 maxColour = (1 << pATI->rgbBits) - 1;
|
|
|
|
pATIHW->dac_read = pATIHW->dac_write = 0x00U;
|
|
pATIHW->dac_mask = 0xFFU;
|
|
|
|
/*
|
|
* Set colour lookup table. The first entry has already been zeroed out.
|
|
*/
|
|
if (pATI->depth > 8)
|
|
for (Index = 1; Index < (NumberOf(pATIHW->lut) / 3); Index++)
|
|
{
|
|
Index2 = Index * 3;
|
|
pATIHW->lut[Index2 + 0] =
|
|
pATIHW->lut[Index2 + 1] =
|
|
pATIHW->lut[Index2 + 2] = Index;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Initialise hardware colour map so that use of uninitialised
|
|
* software colour map entries can easily be seen. For 256-colour
|
|
* modes, this doesn't remain effective for very long...
|
|
*/
|
|
pATIHW->lut[3] = pATIHW->lut[4] = pATIHW->lut[5] = 0xFFU;
|
|
for (Index = 2; Index < (NumberOf(pATIHW->lut) / 3); Index++)
|
|
{
|
|
Index2 = Index * 3;
|
|
pATIHW->lut[Index2 + 0] = maxColour;
|
|
pATIHW->lut[Index2 + 1] = 0x00U;
|
|
pATIHW->lut[Index2 + 2] = maxColour;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ATIDACSave --
|
|
*
|
|
* This function is called to save the current RAMDAC state into an ATIHWRec
|
|
* structure occurrence.
|
|
*/
|
|
void
|
|
ATIDACSave
|
|
(
|
|
ATIPtr pATI,
|
|
ATIHWPtr pATIHW
|
|
)
|
|
{
|
|
int Index;
|
|
|
|
#ifdef AVOID_CPIO
|
|
|
|
pATIHW->dac_read = in8(M64_DAC_READ);
|
|
DACDelay;
|
|
pATIHW->dac_write = in8(M64_DAC_WRITE);
|
|
DACDelay;
|
|
pATIHW->dac_mask = in8(M64_DAC_MASK);
|
|
DACDelay;
|
|
|
|
/* Save DAC's colour lookup table */
|
|
out8(M64_DAC_MASK, 0xFFU);
|
|
DACDelay;
|
|
out8(M64_DAC_READ, 0x00U);
|
|
DACDelay;
|
|
for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
|
|
{
|
|
pATIHW->lut[Index] = in8(M64_DAC_DATA);
|
|
DACDelay;
|
|
}
|
|
|
|
out8(M64_DAC_MASK, pATIHW->dac_mask);
|
|
DACDelay;
|
|
out8(M64_DAC_READ, pATIHW->dac_read);
|
|
DACDelay;
|
|
|
|
#else /* AVOID_CPIO */
|
|
|
|
ATISetDACIOPorts(pATI, pATIHW->crtc);
|
|
|
|
pATIHW->dac_read = inb(pATI->CPIO_DAC_READ);
|
|
DACDelay;
|
|
pATIHW->dac_write = inb(pATI->CPIO_DAC_WRITE);
|
|
DACDelay;
|
|
pATIHW->dac_mask = inb(pATI->CPIO_DAC_MASK);
|
|
DACDelay;
|
|
|
|
/* Save DAC's colour lookup table */
|
|
outb(pATI->CPIO_DAC_MASK, 0xFFU);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_READ, 0x00U);
|
|
DACDelay;
|
|
for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
|
|
{
|
|
pATIHW->lut[Index] = inb(pATI->CPIO_DAC_DATA);
|
|
DACDelay;
|
|
}
|
|
|
|
outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
|
|
DACDelay;
|
|
|
|
#endif /* AVOID_CPIO */
|
|
|
|
}
|
|
|
|
/*
|
|
* ATIDACSet --
|
|
*
|
|
* This function loads RAMDAC data from an ATIHWRec structure occurrence.
|
|
*/
|
|
void
|
|
ATIDACSet
|
|
(
|
|
ATIPtr pATI,
|
|
ATIHWPtr pATIHW
|
|
)
|
|
{
|
|
int Index;
|
|
|
|
#ifdef AVOID_CPIO
|
|
|
|
/* Load DAC's colour lookup table */
|
|
out8(M64_DAC_MASK, 0xFFU);
|
|
DACDelay;
|
|
out8(M64_DAC_WRITE, 0x00U);
|
|
DACDelay;
|
|
for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
|
|
{
|
|
out8(M64_DAC_DATA, pATIHW->lut[Index]);
|
|
DACDelay;
|
|
}
|
|
|
|
out8(M64_DAC_MASK, pATIHW->dac_mask);
|
|
DACDelay;
|
|
out8(M64_DAC_READ, pATIHW->dac_read);
|
|
DACDelay;
|
|
out8(M64_DAC_WRITE, pATIHW->dac_write);
|
|
DACDelay;
|
|
|
|
#else /* AVOID_CPIO */
|
|
|
|
ATISetDACIOPorts(pATI, pATIHW->crtc);
|
|
|
|
/* Load DAC's colour lookup table */
|
|
outb(pATI->CPIO_DAC_MASK, 0xFFU);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_WRITE, 0x00U);
|
|
DACDelay;
|
|
for (Index = 0; Index < NumberOf(pATIHW->lut); Index++)
|
|
{
|
|
outb(pATI->CPIO_DAC_DATA, pATIHW->lut[Index]);
|
|
DACDelay;
|
|
}
|
|
|
|
outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_READ, pATIHW->dac_read);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_WRITE, pATIHW->dac_write);
|
|
DACDelay;
|
|
|
|
#endif /* AVOID_CPIO */
|
|
|
|
}
|
|
|
|
/*
|
|
* ATISetLUTEntry --
|
|
*
|
|
* This function is called to set one of a DAC's LUT entries.
|
|
*/
|
|
static void
|
|
ATISetLUTEntry
|
|
(
|
|
ATIPtr pATI,
|
|
int Index,
|
|
CARD8 *LUTEntry
|
|
)
|
|
{
|
|
#ifdef AVOID_CPIO
|
|
|
|
out8(M64_DAC_WRITE, Index);
|
|
DACDelay;
|
|
out8(M64_DAC_DATA, LUTEntry[0]);
|
|
DACDelay;
|
|
out8(M64_DAC_DATA, LUTEntry[1]);
|
|
DACDelay;
|
|
out8(M64_DAC_DATA, LUTEntry[2]);
|
|
DACDelay;
|
|
|
|
#else /* AVOID_CPIO */
|
|
|
|
outb(pATI->CPIO_DAC_WRITE, Index);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_DATA, LUTEntry[0]);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_DATA, LUTEntry[1]);
|
|
DACDelay;
|
|
outb(pATI->CPIO_DAC_DATA, LUTEntry[2]);
|
|
DACDelay;
|
|
|
|
#endif /* AVOID_CPIO */
|
|
}
|
|
|
|
/*
|
|
* ATILoadPalette --
|
|
*
|
|
* This function updates the RAMDAC's LUT and the in-memory copy of it in
|
|
* NewHW.
|
|
*/
|
|
void
|
|
ATILoadPalette
|
|
(
|
|
ScrnInfoPtr pScreenInfo,
|
|
int nColours,
|
|
int *Indices,
|
|
LOCO *Colours,
|
|
VisualPtr pVisual
|
|
)
|
|
{
|
|
ATIPtr pATI = ATIPTR(pScreenInfo);
|
|
CARD8 *LUTEntry;
|
|
int i, j, Index;
|
|
|
|
if (((pVisual->class | DynamicClass) == DirectColor) &&
|
|
((1 << pVisual->nplanes) > (SizeOf(pATI->NewHW.lut) / 3)))
|
|
{
|
|
int reds = pVisual->redMask >> pVisual->offsetRed;
|
|
int greens = pVisual->greenMask >> pVisual->offsetGreen;
|
|
int blues = pVisual->blueMask >> pVisual->offsetBlue;
|
|
|
|
int redShift = 8 - pATI->weight.red;
|
|
int greenShift = 8 - pATI->weight.green;
|
|
int blueShift = 8 - pATI->weight.blue;
|
|
|
|
int redMult = 3 << redShift;
|
|
int greenMult = 3 << greenShift;
|
|
int blueMult = 3 << blueShift;
|
|
|
|
int minShift;
|
|
|
|
CARD8 fChanged[SizeOf(pATI->NewHW.lut) / 3];
|
|
|
|
(void)memset(fChanged, 0, SizeOf(fChanged));
|
|
|
|
minShift = redShift;
|
|
if (minShift > greenShift)
|
|
minShift = greenShift;
|
|
if (minShift > blueShift)
|
|
minShift = blueShift;
|
|
|
|
for (i = 0; i < nColours; i++)
|
|
{
|
|
if((Index = Indices[i]) < 0)
|
|
continue;
|
|
|
|
if (Index <= reds)
|
|
{
|
|
j = Index * redMult;
|
|
pATI->NewHW.lut[j + 0] = Colours[Index].red;
|
|
fChanged[j / 3] = TRUE;
|
|
}
|
|
if (Index <= greens)
|
|
{
|
|
j = Index * greenMult;
|
|
pATI->NewHW.lut[j + 1] = Colours[Index].green;
|
|
fChanged[j / 3] = TRUE;
|
|
}
|
|
if (Index <= blues)
|
|
{
|
|
j = Index * blueMult;
|
|
pATI->NewHW.lut[j + 2] = Colours[Index].blue;
|
|
fChanged[j / 3] = TRUE;
|
|
}
|
|
}
|
|
|
|
if (pScreenInfo->vtSema || pATI->currentMode)
|
|
{
|
|
/* Rewrite LUT entries that could have been changed */
|
|
i = 1 << minShift;
|
|
LUTEntry = pATI->NewHW.lut;
|
|
|
|
for (Index = 0;
|
|
Index < (SizeOf(pATI->NewHW.lut) / 3);
|
|
Index += i, LUTEntry += i * 3)
|
|
if (fChanged[Index])
|
|
ATISetLUTEntry(pATI, Index, LUTEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < nColours; i++)
|
|
{
|
|
Index = Indices[i];
|
|
if ((Index < 0) || (Index >= (SizeOf(pATI->NewHW.lut) / 3)))
|
|
continue;
|
|
|
|
LUTEntry = &pATI->NewHW.lut[Index * 3];
|
|
LUTEntry[0] = Colours[Index].red;
|
|
LUTEntry[1] = Colours[Index].green;
|
|
LUTEntry[2] = Colours[Index].blue;
|
|
|
|
if (pScreenInfo->vtSema || pATI->currentMode)
|
|
ATISetLUTEntry(pATI, Index, LUTEntry);
|
|
}
|
|
}
|
|
}
|