2079 lines
51 KiB
C
2079 lines
51 KiB
C
/*
|
|
* ______ ____ ______ _____ ______
|
|
* | ____| | _ \| ____| / / _ \| ____|
|
|
* | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
|
|
* | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
|
|
* | | | | | __/ __/ |_) | |____ / / | | | | |
|
|
* |_| |_| \___|\___|____/|______/_/ |_| |_|_|
|
|
*
|
|
*
|
|
* Accelerated Matrox driver, by Shawn Hargreaves.
|
|
*
|
|
* See freebe.txt for copyright information.
|
|
*/
|
|
|
|
// #define NO_HWPTR
|
|
|
|
#include <pc.h>
|
|
|
|
#include "vbeaf.h"
|
|
|
|
/* driver function prototypes */
|
|
void SetBank32( );
|
|
void SetBank32End( );
|
|
int ExtStub( );
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo);
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
|
|
long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc);
|
|
void RestoreTextMode(AF_DRIVER *af);
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock);
|
|
void SaveRestoreState(AF_DRIVER *af, int subfunc, void *saveBuf);
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT);
|
|
void SetActiveBuffer(AF_DRIVER *af, long index);
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT);
|
|
int GetDisplayStartStatus(AF_DRIVER *af);
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index,
|
|
long waitVRT);
|
|
void SetBank(AF_DRIVER *af, long bank);
|
|
void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor);
|
|
void SetCursorPos(AF_DRIVER *af, long x, long y);
|
|
void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green,
|
|
unsigned char blue);
|
|
void ShowCursor(AF_DRIVER *af, long visible);
|
|
void WaitTillIdle(AF_DRIVER *af);
|
|
void SetMix(AF_DRIVER *af, long foreMix, long backMix);
|
|
void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern);
|
|
void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern);
|
|
void Use8x8ColorPattern(AF_DRIVER *af, int index);
|
|
void DrawScan(AF_DRIVER *af, long color, long y, long x1, long x2);
|
|
void DrawPattScan(AF_DRIVER *af, long foreColor, long backColor, long y,
|
|
long x1, long x2);
|
|
void DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2);
|
|
void DrawRect(AF_DRIVER *af, unsigned long color, long left, long top,
|
|
long width, long height);
|
|
void DrawPattRect(AF_DRIVER *af, unsigned long foreColor,
|
|
unsigned long backColor, long left, long top, long width,
|
|
long height);
|
|
void DrawColorPattRect(AF_DRIVER *af, long left, long top, long width,
|
|
long height);
|
|
void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2,
|
|
fixed y2);
|
|
void DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap);
|
|
void PutMonoImage(AF_DRIVER *af, long foreColor, long backColor, long dstX,
|
|
long dstY, long byteWidth, long srcX, long srcY, long width,
|
|
long height, unsigned char *image);
|
|
void BitBlt(AF_DRIVER *af, long left, long top, long width, long height,
|
|
long dstLeft, long dstTop, long op);
|
|
void BitBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft,
|
|
long srcTop, long width, long height, long dstLeft, long dstTop,
|
|
long op);
|
|
void SrcTransBlt(AF_DRIVER *af, long left, long top, long width, long height,
|
|
long dstLeft, long dstTop, long op, unsigned long transparent);
|
|
void SrcTransBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft,
|
|
long srcTop, long width, long height, long dstLeft,
|
|
long dstTop, long op, unsigned long transparent);
|
|
|
|
/* FreeBE/AF extension allowing farptr access to video memory */
|
|
FAF_HWPTR_DATA hwptr;
|
|
|
|
/* mode information from the underlying VESA driver */
|
|
typedef struct VIDEO_MODE {
|
|
int vesa_num;
|
|
int linear;
|
|
int w;
|
|
int h;
|
|
int bpp;
|
|
int bytes_per_scanline;
|
|
int redsize;
|
|
int redpos;
|
|
int greensize;
|
|
int greenpos;
|
|
int bluesize;
|
|
int bluepos;
|
|
int rsvdsize;
|
|
int rsvdpos;
|
|
} VIDEO_MODE;
|
|
|
|
#define MAX_MODES 64
|
|
|
|
VIDEO_MODE mode_list[MAX_MODES];
|
|
|
|
short available_modes[MAX_MODES + 1] = { -1 };
|
|
|
|
int num_modes = 0;
|
|
|
|
unsigned short ports_table[] = { 0xFFFF };
|
|
|
|
/* list of features, so the install program can disable some of them */
|
|
FAF_CONFIG_DATA config_data[] = {
|
|
{ FAF_CFG_FEATURES,
|
|
|
|
(fafLinear | fafBanked | fafHWCursor | fafDrawScan | fafDrawPattScan |
|
|
fafDrawColorPattScan | fafDrawRect | fafDrawPattRect |
|
|
fafDrawColorPattRect | fafDrawLine | fafDrawTrap | fafPutMonoImage |
|
|
fafBitBlt | fafBitBltSys | fafSrcTransBlt | fafSrcTransBltSys) },
|
|
|
|
{ 0, 0 }
|
|
};
|
|
|
|
#define CFG_FEATURES config_data[0].value
|
|
|
|
/* cache eight 8x8 color patterns at the end of vram */
|
|
int pat_off_bytes[8];
|
|
int pat_off_pixels[8];
|
|
|
|
#define PATTERN_VRAM(bpp) ((bpp == 8) ? 512 : ((bpp == 32) ? 3072 : 1536))
|
|
|
|
/* hardware cursors are only supported on the Mystique */
|
|
#define HAS_HW_CURSOR (matrox_id == MATROX_MYST_ID)
|
|
|
|
#define HW_CURSOR_VRAM ((HAS_HW_CURSOR) ? 1024 : 0)
|
|
|
|
int cur_color;
|
|
|
|
int cur_doublemode;
|
|
|
|
int cur_hot_x;
|
|
int cur_hot_y;
|
|
|
|
/* prevent applications from using our reserved video memory */
|
|
#define RESERVED_VRAM(bpp) (PATTERN_VRAM(bpp) + HW_CURSOR_VRAM)
|
|
|
|
/* video mode and driver state information */
|
|
int af_bpp;
|
|
int af_width_bytes;
|
|
int af_width_pixels;
|
|
int af_height;
|
|
int af_visible_page;
|
|
int af_active_page;
|
|
int af_scroll_x;
|
|
int af_scroll_y;
|
|
int af_y;
|
|
int af_fore_mix;
|
|
int af_back_mix;
|
|
int af_color_pattern;
|
|
|
|
AF_PALETTE af_palette[256];
|
|
|
|
/* cached drawing engine state */
|
|
#define OP_NONE 0
|
|
#define OP_DRAWRECT 1
|
|
#define OP_DRAWPATTRECT 2
|
|
#define OP_DRAWCOLORPATTRECT 3
|
|
#define OP_DRAWLINE 4
|
|
#define OP_DRAWTRAP 5
|
|
#define OP_DRAWSLOWTRAP 6
|
|
#define OP_PUTMONOIMAGE_LINEAR 7
|
|
#define OP_PUTMONOIMAGE_SLOW 8
|
|
#define OP_BITBLT_FORWARD 9
|
|
#define OP_BITBLT_BACKWARD 10
|
|
#define OP_BITBLTSYS 11
|
|
#define OP_SRCTRANSBLT 12
|
|
#define OP_SRCTRANSBLTSYS 13
|
|
|
|
int af_operation;
|
|
|
|
/* PCI device identifiers */
|
|
#define MATROX_VENDOR_ID 0x102B
|
|
|
|
#define MATROX_MILL_ID 0x0519
|
|
#define MATROX_MYST_ID 0x051A
|
|
#define MATROX_MII_PCI_ID 0x051B
|
|
#define MATROX_MII_AGP_ID 0x051F
|
|
|
|
int matrox_id_list[] = { MATROX_MILL_ID, MATROX_MYST_ID, MATROX_MII_PCI_ID,
|
|
MATROX_MII_AGP_ID, 0 };
|
|
|
|
int matrox_id;
|
|
int matrox_rev;
|
|
|
|
/* Matrox hardware registers: */
|
|
|
|
#define M_DWGCTL 0x1C00
|
|
#define M_MACCESS 0x1C04
|
|
|
|
#define M_PAT0 0x1C10
|
|
#define M_PAT1 0x1C14
|
|
#define M_PLNWT 0x1C1C
|
|
|
|
#define M_BCOL 0x1C20
|
|
#define M_FCOL 0x1C24
|
|
|
|
#define M_SRC0 0x1C30
|
|
#define M_SRC1 0x1C34
|
|
#define M_SRC2 0x1C38
|
|
#define M_SRC3 0x1C3C
|
|
|
|
#define M_XYSTRT 0x1C40
|
|
#define M_XYEND 0x1C44
|
|
|
|
#define M_SHIFT 0x1C50
|
|
|
|
#define M_SGN 0x1C58
|
|
|
|
#define M_SDXL 0x02
|
|
#define M_SDXR 0x20
|
|
|
|
#define M_LEN 0x1C5C
|
|
|
|
#define M_AR0 0x1C60
|
|
#define M_AR1 0x1C64
|
|
#define M_AR2 0x1C68
|
|
#define M_AR3 0x1C6C
|
|
#define M_AR4 0x1C70
|
|
#define M_AR5 0x1C74
|
|
#define M_AR6 0x1C78
|
|
|
|
#define M_CXBNDRY 0x1C80
|
|
#define M_FXBNDRY 0x1C84
|
|
#define M_YDSTLEN 0x1C88
|
|
#define M_PITCH 0x1C8C
|
|
|
|
#define M_YDST 0x1C90
|
|
#define M_YDSTORG 0x1C94
|
|
#define M_YTOP 0x1C98
|
|
#define M_YBOT 0x1C9C
|
|
|
|
#define M_CXLEFT 0x1CA0
|
|
#define M_CXRIGHT 0x1CA4
|
|
#define M_FXLEFT 0x1CA8
|
|
#define M_FXRIGHT 0x1CAC
|
|
|
|
#define M_XDST 0x1CB0
|
|
|
|
#define M_EXEC 0x0100
|
|
|
|
#define M_FIFOSTATUS 0x1E10
|
|
#define M_STATUS 0x1E14
|
|
#define M_ICLEAR 0x1E18
|
|
#define M_IEN 0x1E1C
|
|
|
|
#define M_VCOUNT 0x1E20
|
|
|
|
#define M_RESET 0x1E40
|
|
|
|
#define M_OPMODE 0x1E54
|
|
|
|
#define M_DMA_GENERAL 0x00
|
|
#define M_DMA_BLIT 0x04
|
|
#define M_DMA_VECTOR 0x40
|
|
|
|
#define M_DWG_LINE_OPEN 0x00
|
|
#define M_DWG_AUTOLINE_OPEN 0x01
|
|
#define M_DWG_LINE_CLOSE 0x02
|
|
#define M_DWG_AUTOLINE_CLOSE 0x03
|
|
|
|
#define M_DWG_TRAP 0x04
|
|
#define M_DWG_TEXTURE_TRAP 0x05
|
|
|
|
#define M_DWG_BITBLT 0x08
|
|
#define M_DWG_FBITBLT 0x0C
|
|
#define M_DWG_ILOAD 0x09
|
|
#define M_DWG_ILOAD_SCALE 0x0D
|
|
#define M_DWG_ILOAD_FILTER 0x0F
|
|
#define M_DWG_IDUMP 0x0A
|
|
|
|
#define M_DWG_LINEAR 0x0080
|
|
#define M_DWG_SOLID 0x0800
|
|
#define M_DWG_ARZERO 0x1000
|
|
#define M_DWG_SGNZERO 0x2000
|
|
#define M_DWG_SHIFTZERO 0x4000
|
|
|
|
#define M_DWG_BPLAN 0x02000000
|
|
#define M_DWG_BFCOL 0x04000000
|
|
#define M_DWG_BMONOWF 0x08000000
|
|
|
|
#define M_DWG_PATTERN 0x20000000
|
|
#define M_DWG_TRANSC 0x40000000
|
|
|
|
#define M_CRTC_INDEX 0x1FD4
|
|
#define M_CRTC_DATA 0x1FD5
|
|
|
|
#define M_CRTC_EXT_INDEX 0x1FDE
|
|
#define M_CRTC_EXT_DATA 0x1FDF
|
|
|
|
/* Mystique-only registers: */
|
|
|
|
#define M_PALWTADD 0x3C00
|
|
#define M_X_DATAREG 0x3C0A
|
|
|
|
#define M_CURPOS 0x3C0C
|
|
|
|
#define M_XCURADDL 0x04
|
|
#define M_XCURADDH 0x05
|
|
|
|
#define M_XCURCTRL 0x06
|
|
|
|
#define M_XCURCOL0RED 0x08
|
|
#define M_XCURCOL0GREEN 0x09
|
|
#define M_XCURCOL0BLUE 0x0A
|
|
#define M_XCURCOL1RED 0x0C
|
|
#define M_XCURCOL1GREEN 0x0D
|
|
#define M_XCURCOL1BLUE 0x0E
|
|
#define M_XCURCOL2RED 0x10
|
|
#define M_XCURCOL2GREEN 0x11
|
|
#define M_XCURCOL2BLUE 0x12
|
|
|
|
#define M_CURCTRL_OFF 0
|
|
#define M_CURCTRL_3COLOR 1
|
|
#define M_CURCTRL_XGA 2
|
|
#define M_CURCTRL_XWINDOWS 3
|
|
|
|
/* helpers for accessing the Matrox registers */
|
|
#define mga_select( ) hwptr_select(hwptr.IOMemMaps[0])
|
|
#define mga_inb(addr) hwptr_nspeekb(hwptr.IOMemMaps[0], addr)
|
|
#define mga_inw(addr) hwptr_nspeekw(hwptr.IOMemMaps[0], addr)
|
|
#define mga_inl(addr) hwptr_nspeekl(hwptr.IOMemMaps[0], addr)
|
|
#define mga_outb(addr, val) hwptr_nspokeb(hwptr.IOMemMaps[0], addr, val)
|
|
#define mga_outw(addr, val) hwptr_nspokew(hwptr.IOMemMaps[0], addr, val)
|
|
#define mga_outl(addr, val) hwptr_nspokel(hwptr.IOMemMaps[0], addr, val)
|
|
|
|
/* mga_xdata:
|
|
* Writes to one of the Mystique cursor control registers.
|
|
*/
|
|
#define mga_xdata(reg, val) \
|
|
{ \
|
|
mga_outb(M_PALWTADD, reg); \
|
|
mga_outb(M_X_DATAREG, val); \
|
|
}
|
|
|
|
/* mga_fifo:
|
|
* Waits until there are at least <n> free slots in the FIFO buffer.
|
|
*/
|
|
#define mga_fifo(n) \
|
|
{ \
|
|
do { } while (mga_inb(M_FIFOSTATUS) < (n)); }
|
|
|
|
/* bswap:
|
|
* Toggles the endianess of a 32 bit integer.
|
|
*/
|
|
unsigned long bswap(unsigned long n) {
|
|
unsigned long a = n & 0xFF;
|
|
unsigned long b = (n >> 8) & 0xFF;
|
|
unsigned long c = (n >> 16) & 0xFF;
|
|
unsigned long d = (n >> 24) & 0xFF;
|
|
|
|
return (a << 24) | (b << 16) | (c << 8) | d;
|
|
}
|
|
|
|
/* mga_wait_retrace:
|
|
* Waits for the next vertical sync period.
|
|
*/
|
|
void mga_wait_retrace(AF_DRIVER *af) {
|
|
int t1 = 0;
|
|
int t2 = 0;
|
|
|
|
do {
|
|
t1 = t2;
|
|
t2 = mga_inl(M_VCOUNT);
|
|
} while (t2 >= t1);
|
|
}
|
|
|
|
/* mode_callback:
|
|
* Callback for the get_vesa_info() function to add a new resolution to
|
|
* the table of available modes.
|
|
*/
|
|
void mode_callback(int vesa_num, int linear, int w, int h, int bpp,
|
|
int bytes_per_scanline, int redsize, int redpos,
|
|
int greensize, int greenpos, int bluesize, int bluepos,
|
|
int rsvdsize, int rsvdpos) {
|
|
if (num_modes >= MAX_MODES) return;
|
|
|
|
if ((bpp != 8) && (bpp != 15) && (bpp != 16) && (bpp != 32)) return;
|
|
|
|
mode_list[num_modes].vesa_num = vesa_num;
|
|
mode_list[num_modes].linear = linear;
|
|
mode_list[num_modes].w = w;
|
|
mode_list[num_modes].h = h;
|
|
mode_list[num_modes].bpp = bpp;
|
|
mode_list[num_modes].bytes_per_scanline = bytes_per_scanline;
|
|
mode_list[num_modes].redsize = redsize;
|
|
mode_list[num_modes].redpos = redpos;
|
|
mode_list[num_modes].greensize = greensize;
|
|
mode_list[num_modes].greenpos = greenpos;
|
|
mode_list[num_modes].bluesize = bluesize;
|
|
mode_list[num_modes].bluepos = bluepos;
|
|
mode_list[num_modes].rsvdsize = rsvdsize;
|
|
mode_list[num_modes].rsvdpos = rsvdpos;
|
|
|
|
available_modes[num_modes] = num_modes + 1;
|
|
available_modes[num_modes + 1] = -1;
|
|
|
|
num_modes++;
|
|
}
|
|
|
|
/* SetupDriver:
|
|
* The first thing ever to be called after our code has been relocated.
|
|
* This is in charge of filling in the driver header with all the required
|
|
* information and function pointers. We do not yet have access to the
|
|
* video memory, so we can't talk directly to the card.
|
|
*/
|
|
int SetupDriver(AF_DRIVER *af) {
|
|
unsigned long pci_base[2];
|
|
int vram_size;
|
|
int bus_id;
|
|
char *name;
|
|
int i;
|
|
|
|
/* find PCI device */
|
|
matrox_id = 0;
|
|
bus_id = 0;
|
|
|
|
for (i = 0; matrox_id_list[i]; i++) {
|
|
if (FindPCIDevice(matrox_id_list[i], MATROX_VENDOR_ID, 0, &bus_id)) {
|
|
matrox_id = matrox_id_list[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!matrox_id) return -1;
|
|
|
|
/* read hardware configuration data */
|
|
matrox_rev = PCIReadLong(bus_id, 8) & 0xFF;
|
|
|
|
for (i = 0; i < 2; i++) pci_base[i] = PCIReadLong(bus_id, 16 + i * 4);
|
|
|
|
/* fetch mode list from the VESA driver */
|
|
if (get_vesa_info(&vram_size, NULL, mode_callback) != 0) return -1;
|
|
|
|
af->AvailableModes = available_modes;
|
|
|
|
af->TotalMemory = vram_size / 1024;
|
|
|
|
af->Attributes = (afHaveMultiBuffer | afHaveVirtualScroll |
|
|
afHaveBankedBuffer | afHaveLinearBuffer | afHaveAccel2D);
|
|
|
|
if (!(CFG_FEATURES & fafLinear)) af->Attributes &= ~afHaveLinearBuffer;
|
|
|
|
if (!(CFG_FEATURES & fafBanked)) af->Attributes &= ~afHaveBankedBuffer;
|
|
|
|
if (HAS_HW_CURSOR) af->Attributes |= afHaveHWCursor;
|
|
|
|
af->BankSize = 64;
|
|
af->BankedBasePtr = 0xA0000;
|
|
|
|
af->IOPortsTable = ports_table;
|
|
|
|
/* work out the linear framebuffer and MMIO addresses */
|
|
if (((matrox_id == MATROX_MYST_ID) && (matrox_rev >= 3)) ||
|
|
(matrox_id == MATROX_MII_PCI_ID) || (matrox_id == MATROX_MII_AGP_ID)) {
|
|
if (pci_base[0]) af->LinearBasePtr = pci_base[0] & 0xFF800000;
|
|
|
|
if (pci_base[1]) af->IOMemoryBase[0] = pci_base[1] & 0xFFFFC000;
|
|
} else {
|
|
if (pci_base[0]) af->IOMemoryBase[0] = pci_base[0] & 0xFFFFC000;
|
|
|
|
if (pci_base[1]) af->LinearBasePtr = pci_base[1] & 0xFF800000;
|
|
}
|
|
|
|
if ((!af->LinearBasePtr) || (!af->IOMemoryBase[0])) return -1;
|
|
|
|
af->LinearSize = vram_size / 1024;
|
|
af->IOMemoryLen[0] = 0x4000;
|
|
|
|
/* set up the driver name */
|
|
switch (matrox_id) {
|
|
case MATROX_MILL_ID: name = "Millenium"; break;
|
|
|
|
case MATROX_MYST_ID: name = "Mystique"; break;
|
|
|
|
case MATROX_MII_PCI_ID: name = "Millenium II PCI"; break;
|
|
|
|
case MATROX_MII_AGP_ID: name = "Millenium II AGP"; break;
|
|
|
|
default: name = "Unknown Matrox"; break;
|
|
}
|
|
|
|
i = 0;
|
|
while (af->OemVendorName[i]) i++;
|
|
|
|
af->OemVendorName[i++] = ',';
|
|
af->OemVendorName[i++] = ' ';
|
|
|
|
while (*name) af->OemVendorName[i++] = *(name++);
|
|
|
|
af->OemVendorName[i] = 0;
|
|
|
|
/* set up driver functions */
|
|
af->SetBank32 = SetBank32;
|
|
af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
|
|
|
|
af->SupplementalExt = ExtStub;
|
|
af->GetVideoModeInfo = GetVideoModeInfo;
|
|
af->SetVideoMode = SetVideoMode;
|
|
af->RestoreTextMode = RestoreTextMode;
|
|
af->GetClosestPixelClock = GetClosestPixelClock;
|
|
af->SaveRestoreState = SaveRestoreState;
|
|
af->SetDisplayStart = SetDisplayStart;
|
|
af->SetActiveBuffer = SetActiveBuffer;
|
|
af->SetVisibleBuffer = SetVisibleBuffer;
|
|
af->GetDisplayStartStatus = GetDisplayStartStatus;
|
|
af->SetPaletteData = SetPaletteData;
|
|
af->SetBank = SetBank;
|
|
af->WaitTillIdle = WaitTillIdle;
|
|
af->SetMix = SetMix;
|
|
af->Set8x8MonoPattern = Set8x8MonoPattern;
|
|
af->DrawScan = DrawScan;
|
|
af->DrawPattScan = DrawPattScan;
|
|
af->DrawRect = DrawRect;
|
|
af->DrawPattRect = DrawPattRect;
|
|
af->DrawLine = DrawLine;
|
|
af->DrawTrap = DrawTrap;
|
|
af->PutMonoImage = PutMonoImage;
|
|
af->BitBlt = BitBlt;
|
|
af->BitBltSys = BitBltSys;
|
|
|
|
fixup_feature_list(af, CFG_FEATURES);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* InitDriver:
|
|
* The second thing to be called during the init process, after the
|
|
* application has mapped all the memory and I/O resources we need.
|
|
* This is in charge of finding the card, returning 0 on success or
|
|
* -1 to abort.
|
|
*/
|
|
int InitDriver(AF_DRIVER *af) {
|
|
/* initialise farptr video memory access */
|
|
hwptr_init(hwptr.IOMemMaps[0], af->IOMemMaps[0]);
|
|
hwptr_init(hwptr.IOMemMaps[1], af->IOMemMaps[1]);
|
|
hwptr_init(hwptr.IOMemMaps[2], af->IOMemMaps[2]);
|
|
hwptr_init(hwptr.IOMemMaps[3], af->IOMemMaps[3]);
|
|
hwptr_init(hwptr.BankedMem, af->BankedMem);
|
|
hwptr_init(hwptr.LinearMem, af->LinearMem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* FreeBEX:
|
|
* Returns an interface structure for the requested FreeBE/AF extension.
|
|
*/
|
|
void *FreeBEX(AF_DRIVER *af, unsigned long id) {
|
|
switch (id) {
|
|
#ifndef NO_HWPTR
|
|
|
|
case FAFEXT_HWPTR:
|
|
/* allow farptr access to video memory */
|
|
return &hwptr;
|
|
|
|
#endif
|
|
|
|
case FAFEXT_CONFIG:
|
|
/* allow the install program to configure our driver */
|
|
return config_data;
|
|
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
/* ExtStub:
|
|
* Vendor-specific extension hook: we don't provide any.
|
|
*/
|
|
int ExtStub( ) {
|
|
return 0;
|
|
}
|
|
|
|
/* GetVideoModeInfo:
|
|
* Retrieves information about this video mode, returning zero on success
|
|
* or -1 if the mode is invalid.
|
|
*/
|
|
long GetVideoModeInfo(AF_DRIVER *af, short mode, AF_MODE_INFO *modeInfo) {
|
|
VIDEO_MODE *info;
|
|
int i;
|
|
|
|
if ((mode <= 0) || (mode > num_modes)) return -1;
|
|
|
|
info = &mode_list[mode - 1];
|
|
|
|
/* clear the structure to zero */
|
|
for (i = 0; i < (int)sizeof(AF_MODE_INFO); i++) ((char *)modeInfo)[i] = 0;
|
|
|
|
/* copy data across from our stored list of mode attributes */
|
|
modeInfo->Attributes = (afHaveMultiBuffer | afHaveVirtualScroll |
|
|
afHaveBankedBuffer | afHaveAccel2D);
|
|
|
|
if (info->linear) {
|
|
modeInfo->Attributes |= afHaveLinearBuffer;
|
|
|
|
if (HAS_HW_CURSOR) modeInfo->Attributes |= afHaveHWCursor;
|
|
}
|
|
|
|
if (!(CFG_FEATURES & fafLinear))
|
|
modeInfo->Attributes &= ~afHaveLinearBuffer;
|
|
|
|
if (!(CFG_FEATURES & fafBanked))
|
|
modeInfo->Attributes &= ~afHaveBankedBuffer;
|
|
|
|
modeInfo->XResolution = info->w;
|
|
modeInfo->YResolution = info->h;
|
|
modeInfo->BitsPerPixel = info->bpp;
|
|
|
|
/* available pages of video memory */
|
|
modeInfo->MaxBuffers = (af->TotalMemory * 1024 - RESERVED_VRAM(info->bpp)) /
|
|
(info->bytes_per_scanline * info->h);
|
|
|
|
/* maximum virtual scanline length in both bytes and pixels */
|
|
modeInfo->MaxBytesPerScanLine = 2048 * BYTES_PER_PIXEL(info->bpp);
|
|
modeInfo->MaxScanLineWidth = 2048;
|
|
|
|
/* for banked video modes, fill in these variables: */
|
|
modeInfo->BytesPerScanLine = info->bytes_per_scanline;
|
|
modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
|
|
modeInfo->RedMaskSize = info->redsize;
|
|
modeInfo->RedFieldPosition = info->redpos;
|
|
modeInfo->GreenMaskSize = info->greensize;
|
|
modeInfo->GreenFieldPosition = info->greenpos;
|
|
modeInfo->BlueMaskSize = info->bluesize;
|
|
modeInfo->BlueFieldPosition = info->bluepos;
|
|
modeInfo->RsvdMaskSize = info->rsvdsize;
|
|
modeInfo->RsvdFieldPosition = info->rsvdpos;
|
|
|
|
/* for linear video modes, fill in these variables: */
|
|
modeInfo->LinBytesPerScanLine = info->bytes_per_scanline;
|
|
modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
|
|
modeInfo->LinRedMaskSize = info->redsize;
|
|
modeInfo->LinRedFieldPosition = info->redpos;
|
|
modeInfo->LinGreenMaskSize = info->greensize;
|
|
modeInfo->LinGreenFieldPosition = info->greenpos;
|
|
modeInfo->LinBlueMaskSize = info->bluesize;
|
|
modeInfo->LinBlueFieldPosition = info->bluepos;
|
|
modeInfo->LinRsvdMaskSize = info->rsvdsize;
|
|
modeInfo->LinRsvdFieldPosition = info->rsvdpos;
|
|
|
|
/* I'm not sure exactly what these should be: Allegro doesn't use them */
|
|
modeInfo->MaxPixelClock = 135000000;
|
|
modeInfo->VideoCapabilities = 0;
|
|
modeInfo->VideoMinXScale = 0;
|
|
modeInfo->VideoMinYScale = 0;
|
|
modeInfo->VideoMaxXScale = 0;
|
|
modeInfo->VideoMaxYScale = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* SetVideoMode:
|
|
* Sets the specified video mode, returning zero on success.
|
|
*
|
|
* Possible flag bits that may be or'ed with the mode number:
|
|
*
|
|
* 0x8000 = don't clear video memory
|
|
* 0x4000 = enable linear framebuffer
|
|
* 0x2000 = enable multi buffering
|
|
* 0x1000 = enable virtual scrolling
|
|
* 0x0800 = use refresh rate control
|
|
* 0x0400 = use hardware stereo
|
|
*/
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
|
|
long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc) {
|
|
static int millenium_strides[] = { 640, 768, 800, 960, 1024, 1152,
|
|
1280, 1600, 1920, 2048, 0 };
|
|
|
|
/* for some reason, 800 pixel wide screens seem to upset the drawing
|
|
* engine on my Mystique. I fixed this by leaving them out of this table,
|
|
* so the virtual width will be rounded up to 832: this seems to correct
|
|
* the problem, but I've no idea why! According to the specs, 800 should
|
|
* be a valid pitch.
|
|
*/
|
|
static int mystique_strides[] = { 512, 640, 768, 832, 960, 1024, 1152,
|
|
1280, 1600, 1664, 1920, 2048, 0 };
|
|
|
|
int linear = ((mode & 0x4000) != 0);
|
|
int noclear = ((mode & 0x8000) != 0);
|
|
long available_vram;
|
|
long used_vram;
|
|
int *strides;
|
|
VIDEO_MODE *info;
|
|
RM_REGS r;
|
|
int i;
|
|
|
|
/* reject anything with hardware stereo */
|
|
if (mode & 0x400) return -1;
|
|
|
|
/* reject linear/banked modes if the install program has disabled them */
|
|
if (linear) {
|
|
if (!(CFG_FEATURES & fafLinear)) return -1;
|
|
} else {
|
|
if (!(CFG_FEATURES & fafBanked)) return -1;
|
|
}
|
|
|
|
/* mask off the other flag bits */
|
|
mode &= 0x3FF;
|
|
|
|
if ((mode <= 0) || (mode > num_modes)) return -1;
|
|
|
|
info = &mode_list[mode - 1];
|
|
|
|
/* reject the linear flag if the mode doesn't support it */
|
|
if ((linear) && (!info->linear)) return -1;
|
|
|
|
/* call VESA to set the mode */
|
|
r.x.ax = 0x4F02;
|
|
r.x.bx = info->vesa_num;
|
|
if (linear) r.x.bx |= 0x4000;
|
|
if (noclear) r.x.bx |= 0x8000;
|
|
rm_int(0x10, &r);
|
|
if (r.h.ah) return -1;
|
|
|
|
/* round the virtual width up to a suitable value */
|
|
*bytesPerLine =
|
|
MAX(info->bytes_per_scanline, virtualX * BYTES_PER_PIXEL(info->bpp));
|
|
|
|
if (matrox_id == MATROX_MYST_ID)
|
|
strides = mystique_strides;
|
|
else
|
|
strides = millenium_strides;
|
|
|
|
for (i = 0; strides[i]; i++) {
|
|
if (*bytesPerLine <= strides[i] * BYTES_PER_PIXEL(info->bpp)) {
|
|
*bytesPerLine = strides[i] * BYTES_PER_PIXEL(info->bpp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* wider than this would overflow the 7k window used by BitBltSys() */
|
|
if (*bytesPerLine > 4096) return -1;
|
|
|
|
/* adjust the virtual screen width */
|
|
if (matrox_id != MATROX_MILL_ID) {
|
|
write_vga_register(0x3D4, 0x13, (*bytesPerLine / 16) & 0xFF);
|
|
alter_vga_register(0x3DE, 0, 0x30, ((*bytesPerLine / 16) >> 4) & 0x30);
|
|
} else {
|
|
write_vga_register(0x3D4, 0x13, (*bytesPerLine / 8) & 0xFF);
|
|
alter_vga_register(0x3DE, 0, 0x30, ((*bytesPerLine / 8) >> 4) & 0x30);
|
|
}
|
|
|
|
/* store info about the current mode */
|
|
af_bpp = info->bpp;
|
|
af_width_bytes = *bytesPerLine;
|
|
af_width_pixels = *bytesPerLine / BYTES_PER_PIXEL(af_bpp);
|
|
af_height = MAX(info->h, virtualY);
|
|
af_visible_page = 0;
|
|
af_active_page = 0;
|
|
af_scroll_x = 0;
|
|
af_scroll_y = 0;
|
|
af_y = 0;
|
|
|
|
/* return framebuffer dimensions to the application */
|
|
af->BufferEndX = af_width_pixels - 1;
|
|
af->BufferEndY = af_height - 1;
|
|
af->OriginOffset = 0;
|
|
|
|
used_vram = af_width_bytes * af_height * numBuffers;
|
|
available_vram = af->TotalMemory * 1024 - RESERVED_VRAM(af_bpp);
|
|
|
|
if (used_vram > available_vram) return -1;
|
|
|
|
if (available_vram - used_vram >= af_width_bytes) {
|
|
af->OffscreenOffset = used_vram;
|
|
af->OffscreenStartY = af_height * numBuffers;
|
|
af->OffscreenEndY = available_vram / af_width_bytes - 1;
|
|
} else {
|
|
af->OffscreenOffset = 0;
|
|
af->OffscreenStartY = 0;
|
|
af->OffscreenEndY = 0;
|
|
}
|
|
|
|
af_fore_mix = AF_REPLACE_MIX;
|
|
af_back_mix = AF_FORE_MIX;
|
|
|
|
af_color_pattern = 0;
|
|
|
|
af_operation = OP_NONE;
|
|
|
|
/* set up the accelerator engine */
|
|
mga_select( );
|
|
|
|
mga_fifo(8);
|
|
mga_outl(M_PITCH, af_width_pixels);
|
|
mga_outl(M_YDSTORG, 0);
|
|
mga_outl(M_PLNWT, 0xFFFFFFFF);
|
|
mga_outl(M_OPMODE, M_DMA_BLIT);
|
|
mga_outl(M_CXBNDRY, 0xFFFF0000);
|
|
mga_outl(M_YTOP, 0x00000000);
|
|
mga_outl(M_YBOT, 0x007FFFFF);
|
|
|
|
switch (af_bpp) {
|
|
case 8: mga_outl(M_MACCESS, 0); break;
|
|
|
|
case 15: mga_outl(M_MACCESS, 0xC0000001); break;
|
|
|
|
case 16: mga_outl(M_MACCESS, 0x40000001); break;
|
|
|
|
case 32: mga_outl(M_MACCESS, 2); break;
|
|
}
|
|
|
|
/* only enable colored patterns and hardware cursors in linear modes */
|
|
if (linear) {
|
|
af->Set8x8ColorPattern = Set8x8ColorPattern;
|
|
af->Use8x8ColorPattern = Use8x8ColorPattern;
|
|
af->DrawColorPattScan = DrawColorPattScan;
|
|
af->DrawColorPattRect = DrawColorPattRect;
|
|
|
|
if (HAS_HW_CURSOR) {
|
|
af->SetCursor = SetCursor;
|
|
af->SetCursorPos = SetCursorPos;
|
|
af->SetCursorColor = SetCursorColor;
|
|
af->ShowCursor = ShowCursor;
|
|
|
|
cur_doublemode = (info->h < 400);
|
|
cur_color = -1;
|
|
} else {
|
|
af->SetCursor = NULL;
|
|
af->SetCursorPos = NULL;
|
|
af->SetCursorColor = NULL;
|
|
af->ShowCursor = NULL;
|
|
}
|
|
} else {
|
|
af->Set8x8ColorPattern = NULL;
|
|
af->Use8x8ColorPattern = NULL;
|
|
af->DrawColorPattScan = NULL;
|
|
af->DrawColorPattRect = NULL;
|
|
|
|
af->SetCursor = NULL;
|
|
af->SetCursorPos = NULL;
|
|
af->SetCursorColor = NULL;
|
|
af->ShowCursor = NULL;
|
|
}
|
|
|
|
/* masked blitting is only possible on the Mystique */
|
|
if (matrox_id != MATROX_MILL_ID) {
|
|
af->SrcTransBlt = SrcTransBlt;
|
|
|
|
/* in truecolor modes, this is faster without using the hardware! */
|
|
if (af_bpp == 8)
|
|
af->SrcTransBltSys = SrcTransBltSys;
|
|
else
|
|
af->SrcTransBltSys = NULL;
|
|
}
|
|
|
|
/* deal with odd alignment/interleaving rules for color pattern data */
|
|
i = (af->TotalMemory * 1024 - HW_CURSOR_VRAM) / BYTES_PER_PIXEL(af_bpp);
|
|
|
|
if (af_bpp == 8) {
|
|
pat_off_pixels[0] = i - 512;
|
|
pat_off_pixels[1] = i - 512 + 8;
|
|
pat_off_pixels[2] = i - 512 + 16;
|
|
pat_off_pixels[3] = i - 512 + 24;
|
|
pat_off_pixels[4] = i - 256;
|
|
pat_off_pixels[5] = i - 256 + 8;
|
|
pat_off_pixels[6] = i - 256 + 16;
|
|
pat_off_pixels[7] = i - 256 + 24;
|
|
} else {
|
|
pat_off_pixels[0] = i - 768;
|
|
pat_off_pixels[1] = i - 768 + 8;
|
|
pat_off_pixels[2] = i - 768 + 16;
|
|
pat_off_pixels[3] = i - 512;
|
|
pat_off_pixels[4] = i - 512 + 8;
|
|
pat_off_pixels[5] = i - 512 + 16;
|
|
pat_off_pixels[6] = i - 256;
|
|
pat_off_pixels[7] = i - 256 + 8;
|
|
}
|
|
|
|
for (i = 0; i < 8; i++)
|
|
pat_off_bytes[i] = pat_off_pixels[i] * BYTES_PER_PIXEL(af_bpp);
|
|
|
|
fixup_feature_list(af, CFG_FEATURES);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* RestoreTextMode:
|
|
* Returns to text mode, shutting down the accelerator hardware.
|
|
*/
|
|
void RestoreTextMode(AF_DRIVER *af) {
|
|
RM_REGS r;
|
|
|
|
r.x.ax = 3;
|
|
rm_int(0x10, &r);
|
|
}
|
|
|
|
/* GetClosestPixelClock:
|
|
* I don't have a clue what this should return: it is used for the
|
|
* refresh rate control.
|
|
*/
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock) {
|
|
/* ??? */
|
|
return 135000000;
|
|
}
|
|
|
|
/* SaveRestoreState:
|
|
* Stores the current driver status: not presently implemented.
|
|
*/
|
|
void SaveRestoreState(AF_DRIVER *af, int subfunc, void *saveBuf) {
|
|
/* not implemented (not used by Allegro) */
|
|
}
|
|
|
|
/* SetDisplayStart:
|
|
* Hardware scrolling function.
|
|
*/
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT) {
|
|
long addr;
|
|
|
|
mga_select( );
|
|
|
|
if (waitVRT >= 0) {
|
|
if ((waitVRT) && (matrox_id == MATROX_MYST_ID)) mga_wait_retrace(af);
|
|
|
|
addr = (((y + af_visible_page * af_height) * af_width_bytes) +
|
|
(x * BYTES_PER_PIXEL(af_bpp)));
|
|
|
|
if (matrox_id != MATROX_MILL_ID)
|
|
addr /= 8;
|
|
else
|
|
addr /= 4;
|
|
|
|
write_vga_register(0x3D4, 0x0D, (addr)&0xFF);
|
|
write_vga_register(0x3D4, 0x0C, (addr >> 8) & 0xFF);
|
|
alter_vga_register(0x3DE, 0, 0x0F, (addr >> 16) & 0x0F);
|
|
|
|
if ((waitVRT) && (matrox_id != MATROX_MYST_ID)) mga_wait_retrace(af);
|
|
}
|
|
|
|
af_scroll_x = x;
|
|
af_scroll_y = y;
|
|
}
|
|
|
|
/* SetActiveBuffer:
|
|
* Sets which buffer is being drawn onto, for use in multi buffering
|
|
* systems (not used by Allegro).
|
|
*/
|
|
void SetActiveBuffer(AF_DRIVER *af, long index) {
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY += af_active_page * af_height;
|
|
af->OffscreenEndY += af_active_page * af_height;
|
|
}
|
|
|
|
af_active_page = index;
|
|
af_y = index * af_height;
|
|
|
|
af_operation = OP_NONE;
|
|
|
|
af->OriginOffset = af_width_bytes * af_height * index;
|
|
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY -= af_active_page * af_height;
|
|
af->OffscreenEndY -= af_active_page * af_height;
|
|
}
|
|
}
|
|
|
|
/* SetVisibleBuffer:
|
|
* Sets which buffer is displayed on the screen, for use in multi buffering
|
|
* systems (not used by Allegro).
|
|
*/
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT) {
|
|
af_visible_page = index;
|
|
|
|
SetDisplayStart(af, af_scroll_x, af_scroll_y, waitVRT);
|
|
}
|
|
|
|
/* GetDisplayStartStatus:
|
|
* Status poll for triple buffering. Not possible on the majority of
|
|
* present cards: this function is just a placeholder.
|
|
*/
|
|
int GetDisplayStartStatus(AF_DRIVER *af) {
|
|
return 1;
|
|
}
|
|
|
|
/* SetPaletteData:
|
|
* Palette setting routine.
|
|
*/
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index,
|
|
long waitVRT) {
|
|
int i;
|
|
|
|
mga_select( );
|
|
|
|
if (waitVRT) mga_wait_retrace(af);
|
|
|
|
for (i = 0; i < num; i++) {
|
|
outportb(0x3C8, index + i);
|
|
outportb(0x3C9, pal[i].red / 4);
|
|
outportb(0x3C9, pal[i].green / 4);
|
|
outportb(0x3C9, pal[i].blue / 4);
|
|
|
|
af_palette[index + i] = pal[i];
|
|
}
|
|
|
|
if ((af_bpp == 8) && (cur_color >= 0) &&
|
|
(((cur_color >= index) && (cur_color < index + num)) || (index == 0)))
|
|
SetCursorColor(af, cur_color, 0, 0);
|
|
}
|
|
|
|
/* SetBank32:
|
|
* Relocatable bank switch function. This is called with a bank number in
|
|
* %edx.
|
|
*/
|
|
|
|
asm ("
|
|
|
|
.globl _SetBank32, _SetBank32End
|
|
|
|
.align 4
|
|
_SetBank32:
|
|
pushl %eax
|
|
pushl %edx
|
|
movb %dl, %ah
|
|
movb $4, %al
|
|
movw $0x03DE, %dx
|
|
outw %ax, %dx
|
|
popl %edx
|
|
popl %eax
|
|
ret
|
|
|
|
_SetBank32End:
|
|
|
|
");
|
|
|
|
|
|
|
|
/* SetBank:
|
|
* C-callable bank switch function. This version simply chains to the
|
|
* relocatable SetBank32() above.
|
|
*/
|
|
void SetBank(AF_DRIVER *af, long bank)
|
|
{
|
|
asm(" call _SetBank32 " : : "d"(bank));
|
|
}
|
|
|
|
|
|
|
|
/* SetCursor:
|
|
* Sets the hardware cursor shape.
|
|
*/
|
|
void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor)
|
|
{
|
|
int addr = af->TotalMemory * 1024 - HW_CURSOR_VRAM;
|
|
int p = addr;
|
|
int i;
|
|
|
|
hwptr_select(hwptr.LinearMem);
|
|
|
|
if (cur_doublemode) {
|
|
for (i = 0; i < 32; i++) {
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(cursor->xorMask[i]));
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0xFFFFFFFF);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(~cursor->andMask[i]));
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(cursor->xorMask[i]));
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0xFFFFFFFF);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(~cursor->andMask[i]));
|
|
p += 4;
|
|
}
|
|
} else {
|
|
for (i = 0; i < 32; i++) {
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(cursor->xorMask[i]));
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0xFFFFFFFF);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, bswap(~cursor->andMask[i]));
|
|
p += 4;
|
|
}
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0xFFFFFFFF);
|
|
p += 4;
|
|
hwptr_nspokel(hwptr.LinearMem, p, 0xFFFFFFFF);
|
|
p += 4;
|
|
}
|
|
}
|
|
|
|
mga_select( );
|
|
|
|
mga_xdata(M_XCURADDL, (addr / 1024) & 0xFF);
|
|
mga_xdata(M_XCURADDH, (addr / 1024) >> 8);
|
|
|
|
cur_hot_x = cursor->hotx;
|
|
cur_hot_y = cursor->hoty;
|
|
}
|
|
|
|
|
|
|
|
/* SetCursorPos:
|
|
* Sets the hardware cursor position.
|
|
*/
|
|
void SetCursorPos(AF_DRIVER *af, long x, long y)
|
|
{
|
|
x -= cur_hot_x;
|
|
y -= cur_hot_y;
|
|
|
|
mga_select( );
|
|
|
|
if (cur_doublemode) y *= 2;
|
|
|
|
mga_outl(M_CURPOS, ((y + 64) << 16) | (x + 64));
|
|
}
|
|
|
|
|
|
|
|
/* SetCursorColor:
|
|
* Sets the hardware cursor color.
|
|
*/
|
|
void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green, unsigned char blue)
|
|
{
|
|
int r2, g2, b2;
|
|
|
|
mga_select( );
|
|
|
|
if (af_bpp == 8) {
|
|
cur_color = red;
|
|
|
|
red = af_palette[cur_color].red;
|
|
green = af_palette[cur_color].green;
|
|
blue = af_palette[cur_color].blue;
|
|
|
|
r2 = af_palette[0].red;
|
|
g2 = af_palette[0].green;
|
|
b2 = af_palette[0].blue;
|
|
} else {
|
|
cur_color = -1;
|
|
|
|
r2 = ~red;
|
|
g2 = ~green;
|
|
b2 = ~blue;
|
|
}
|
|
|
|
mga_xdata(M_XCURCOL0RED, r2);
|
|
mga_xdata(M_XCURCOL0GREEN, g2);
|
|
mga_xdata(M_XCURCOL0BLUE, b2);
|
|
mga_xdata(M_XCURCOL1RED, red);
|
|
mga_xdata(M_XCURCOL1GREEN, green);
|
|
mga_xdata(M_XCURCOL1BLUE, blue);
|
|
}
|
|
|
|
|
|
|
|
/* ShowCursor:
|
|
* Turns the hardware cursor on or off.
|
|
*/
|
|
void ShowCursor(AF_DRIVER *af, long visible)
|
|
{
|
|
mga_select( );
|
|
|
|
mga_xdata(M_XCURCTRL, (visible) ? M_CURCTRL_XGA : M_CURCTRL_OFF);
|
|
}
|
|
|
|
|
|
|
|
/* WaitTillIdle:
|
|
* Delay until the hardware controller has finished drawing.
|
|
*/
|
|
void WaitTillIdle(AF_DRIVER *af)
|
|
{
|
|
FAF_HWPTR oldptr;
|
|
int tries = 2;
|
|
|
|
hwptr_unselect(oldptr);
|
|
|
|
mga_select( );
|
|
|
|
while (tries--) {
|
|
do {
|
|
} while (!(mga_inl(M_FIFOSTATUS) & 0x200));
|
|
|
|
do {
|
|
} while (mga_inl(M_STATUS) & 0x10000);
|
|
|
|
mga_outb(M_CRTC_INDEX, 0);
|
|
}
|
|
|
|
hwptr_select(oldptr);
|
|
}
|
|
|
|
|
|
|
|
/* mga_mix:
|
|
* Returns drawing engine control flags for the specified VBE/AF mix mode.
|
|
*/
|
|
long mga_mix(int mix)
|
|
{
|
|
switch (mix) {
|
|
case AF_REPLACE_MIX: return 0x000C0040;
|
|
|
|
case AF_AND_MIX: return 0x00080010;
|
|
|
|
case AF_OR_MIX: return 0x000E0010;
|
|
|
|
case AF_XOR_MIX: return 0x00060010;
|
|
|
|
default: return 0x000A0010;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* mga_mix_noblk:
|
|
* Returns drawing engine control flags for the specified VBE/AF mix mode.
|
|
*/
|
|
long mga_mix_noblk(int mix)
|
|
{
|
|
switch (mix) {
|
|
case AF_REPLACE_MIX: return 0x000C0000;
|
|
|
|
case AF_AND_MIX: return 0x00080010;
|
|
|
|
case AF_OR_MIX: return 0x000E0010;
|
|
|
|
case AF_XOR_MIX: return 0x00060010;
|
|
|
|
default: return 0x000A0010;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SetMix:
|
|
* Specifies the pixel mix mode to be used for hardware drawing functions.
|
|
*/
|
|
void SetMix(AF_DRIVER *af, long foreMix, long backMix)
|
|
{
|
|
af_fore_mix = foreMix;
|
|
af_back_mix = backMix;
|
|
|
|
af_operation = OP_NONE;
|
|
}
|
|
|
|
|
|
|
|
/* Set8x8MonoPattern:
|
|
* Downloads a monochrome (packed bit) pattern, for use by the
|
|
* DrawPattScan() and DrawPattRect() functions. This is always sized
|
|
* 8x8, and aligned with the top left corner of video memory: if other
|
|
* alignments are desired, the pattern will be prerotated before it
|
|
* is passed to this routine.
|
|
*/
|
|
void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern)
|
|
{
|
|
unsigned long d1, d2;
|
|
|
|
d1 = pattern[0] | (pattern[1] << 8) | (pattern[2] << 16) |
|
|
(pattern[3] << 24);
|
|
d2 = pattern[4] | (pattern[5] << 8) | (pattern[6] << 16) |
|
|
(pattern[7] << 24);
|
|
|
|
mga_select( );
|
|
|
|
mga_fifo(2);
|
|
mga_outl(M_PAT0, d1);
|
|
mga_outl(M_PAT1, d2);
|
|
}
|
|
|
|
|
|
|
|
/* Set8x8ColorPattern:
|
|
* Downloads a color pattern, for use by the DrawColorPattScan() and
|
|
* DrawColorPattRect() functions. This is always sized 8x8, and aligned
|
|
* with the top left corner of video memory: if other alignments are
|
|
* desired, the pattern will be prerotated before it is passed to this
|
|
* routine. The color values are presented in the native format for
|
|
* the current video mode, but padded to 32 bits (so the pattern is
|
|
* always an 8x8 array of longs).
|
|
*/
|
|
void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
|
|
{
|
|
int p = pat_off_bytes[index];
|
|
int x, y;
|
|
|
|
hwptr_select(hwptr.LinearMem);
|
|
|
|
switch (af_bpp) {
|
|
case 8:
|
|
for (y = 0; y < 8; y++)
|
|
for (x = 0; x < 8; x++)
|
|
hwptr_nspokeb(hwptr.LinearMem, p + (y * 32 + x),
|
|
pattern[y * 8 + x]);
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
for (y = 0; y < 8; y++)
|
|
for (x = 0; x < 8; x++)
|
|
hwptr_nspokew(hwptr.LinearMem, p + (y * 32 + x) * 2,
|
|
pattern[y * 8 + x]);
|
|
break;
|
|
|
|
case 32:
|
|
for (y = 0; y < 8; y++)
|
|
for (x = 0; x < 8; x++)
|
|
hwptr_nspokel(hwptr.LinearMem, p + (y * 32 + x) * 4,
|
|
pattern[y * 8 + x]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Use8x8ColorPattern:
|
|
* Selects one of the patterns previously downloaded by Set8x8ColorPattern().
|
|
*/
|
|
void Use8x8ColorPattern(AF_DRIVER *af, int index)
|
|
{
|
|
af_color_pattern = index;
|
|
}
|
|
|
|
|
|
|
|
/* DrawScan:
|
|
* Fills a scanline in the current foreground mix mode. Draws up to but
|
|
* not including the second x coordinate. If the second coord is less
|
|
* than the first, they are swapped. If they are equal, nothing is drawn.
|
|
*/
|
|
void DrawScan(AF_DRIVER *af, long color, long y, long x1, long x2)
|
|
{
|
|
if (x1 < x2)
|
|
DrawRect(af, color, x1, y, x2 - x1, 1);
|
|
else if (x2 < x1)
|
|
DrawRect(af, color, x2, y, x1 - x2, 1);
|
|
}
|
|
|
|
|
|
|
|
/* DrawPattScan:
|
|
* Fills a scanline using the current mono pattern. Set pattern bits are
|
|
* drawn using the specified foreground color and the foreground mix
|
|
* mode, and clear bits use the background color and background mix mode.
|
|
*/
|
|
void DrawPattScan(AF_DRIVER *af, long foreColor, long backColor, long y, long x1, long x2)
|
|
{
|
|
if (x1 < x2)
|
|
DrawPattRect(af, foreColor, backColor, x1, y, x2 - x1, 1);
|
|
else if (x2 < x1)
|
|
DrawPattRect(af, foreColor, backColor, x2, y, x1 - x2, 1);
|
|
}
|
|
|
|
|
|
|
|
/* DrawColorPattScan:
|
|
* Fills a scanline using the current color pattern and mix mode.
|
|
*/
|
|
void DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2)
|
|
{
|
|
if (x1 < x2)
|
|
DrawColorPattRect(af, x1, y, x2 - x1, 1);
|
|
else if (x2 < x1)
|
|
DrawColorPattRect(af, x2, y, x1 - x2, 1);
|
|
}
|
|
|
|
|
|
|
|
/* DrawRect:
|
|
* Fills a rectangle in the current foreground mix mode.
|
|
*/
|
|
void DrawRect(AF_DRIVER *af, unsigned long color, long left, long top, long width, long height)
|
|
{
|
|
long cmd;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWRECT) {
|
|
cmd = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO |
|
|
M_DWG_SHIFTZERO;
|
|
|
|
if ((matrox_id == MATROX_MII_PCI_ID) ||
|
|
(matrox_id == MATROX_MII_AGP_ID))
|
|
cmd |= M_DWG_TRANSC;
|
|
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, cmd | mga_mix(af_fore_mix));
|
|
|
|
af_operation = OP_DRAWRECT;
|
|
}
|
|
|
|
/* make the color a dword */
|
|
if (af_bpp == 8) {
|
|
color |= color << 8;
|
|
color |= color << 16;
|
|
} else if (af_bpp < 32) {
|
|
color |= color << 16;
|
|
}
|
|
|
|
/* draw the rectangle */
|
|
mga_fifo(3);
|
|
mga_outl(M_FCOL, color);
|
|
mga_outl(M_FXBNDRY, ((left + width) << 16) | left);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((top + af_y) << 16) | height);
|
|
}
|
|
|
|
|
|
|
|
/* DrawPattRect:
|
|
* Fills a rectangle using the current mono pattern. Set pattern bits are
|
|
* drawn using the specified foreground color and the foreground mix
|
|
* mode, and clear bits use the background color and background mix mode.
|
|
*/
|
|
void DrawPattRect(AF_DRIVER *af, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height)
|
|
{
|
|
long cmd;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWPATTRECT) {
|
|
cmd = M_DWG_TRAP | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
|
|
|
|
if (af_back_mix == AF_NOP_MIX)
|
|
cmd |= mga_mix(af_fore_mix) | M_DWG_TRANSC;
|
|
else
|
|
cmd |= mga_mix_noblk(af_fore_mix);
|
|
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, cmd);
|
|
|
|
af_operation = OP_DRAWPATTRECT;
|
|
}
|
|
|
|
/* make the color a dword */
|
|
if (af_bpp == 8) {
|
|
foreColor |= foreColor << 8;
|
|
foreColor |= foreColor << 16;
|
|
} else if (af_bpp < 32) {
|
|
foreColor |= foreColor << 16;
|
|
}
|
|
|
|
/* sort out the background color */
|
|
if (af_back_mix == AF_NOP_MIX) {
|
|
backColor = 0;
|
|
} else {
|
|
if (af_bpp == 8) {
|
|
backColor |= backColor << 8;
|
|
backColor |= backColor << 16;
|
|
} else if (af_bpp < 32) {
|
|
backColor |= backColor << 16;
|
|
}
|
|
}
|
|
|
|
/* draw the rectangle */
|
|
mga_fifo(4);
|
|
mga_outl(M_FCOL, foreColor);
|
|
mga_outl(M_BCOL, backColor);
|
|
mga_outl(M_FXBNDRY, ((left + width) << 16) | left);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((top + af_y) << 16) | height);
|
|
}
|
|
|
|
|
|
|
|
/* DrawColorPattRect:
|
|
* Fills a rectangle using the current color pattern and mix mode.
|
|
*/
|
|
void DrawColorPattRect(AF_DRIVER *af, long left, long top, long width, long height)
|
|
{
|
|
int addr, addr2, offs;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWCOLORPATTRECT) {
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO |
|
|
M_DWG_BFCOL | M_DWG_PATTERN |
|
|
mga_mix_noblk(af_fore_mix));
|
|
|
|
af_operation = OP_DRAWCOLORPATTRECT;
|
|
}
|
|
|
|
/* calculate pattern address */
|
|
addr =
|
|
pat_off_pixels[af_color_pattern] + (left & 7) + ((top + af_y) & 7) * 32;
|
|
offs = (af_bpp == 8) ? 2 : ((af_bpp == 32) ? 6 : 4);
|
|
addr2 = ((addr + offs) & 7) | (addr & 0xFFFFFFF8);
|
|
|
|
/* draw the rectangle */
|
|
mga_fifo(5);
|
|
mga_outl(M_AR0, addr2);
|
|
mga_outl(M_AR3, addr);
|
|
mga_outl(M_AR5, 32);
|
|
mga_outl(M_FXBNDRY, ((left + width - 1) << 16) | left);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((top + af_y) << 16) | height);
|
|
}
|
|
|
|
|
|
|
|
/* DrawLine:
|
|
* Draws a line, using the current foreground mix mode.
|
|
*/
|
|
void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2)
|
|
{
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWLINE) {
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, M_DWG_AUTOLINE_CLOSE | M_DWG_SOLID |
|
|
M_DWG_SHIFTZERO | mga_mix_noblk(af_fore_mix));
|
|
|
|
af_operation = OP_DRAWLINE;
|
|
}
|
|
|
|
/* make the color a dword */
|
|
if (af_bpp == 8) {
|
|
color |= color << 8;
|
|
color |= color << 16;
|
|
} else if (af_bpp < 32) {
|
|
color |= color << 16;
|
|
}
|
|
|
|
/* round coordinates from fixed point to integer */
|
|
x1 = (x1 + 0x8000) >> 16;
|
|
y1 = (y1 + 0x8000) >> 16;
|
|
x2 = (x2 + 0x8000) >> 16;
|
|
y2 = (y2 + 0x8000) >> 16;
|
|
|
|
/* draw the line */
|
|
mga_fifo(3);
|
|
mga_outl(M_FCOL, color);
|
|
mga_outl(M_XYSTRT, ((y1 + af_y) << 16) | x1);
|
|
mga_outl(M_XYEND | M_EXEC, ((y2 + af_y) << 16) | x2);
|
|
}
|
|
|
|
|
|
|
|
/* DrawSlowTrap:
|
|
* Special case trapezoid filler, for handling cases where the two edges
|
|
* cross. I'm not sure if this is allowed to happen, but I'd rather support
|
|
* it just in case :-)
|
|
*/
|
|
static void DrawSlowTrap(AF_DRIVER *af, AF_TRAP *trap)
|
|
{
|
|
int ix1, ix2;
|
|
long cmd;
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWSLOWTRAP) {
|
|
cmd = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO |
|
|
M_DWG_SHIFTZERO;
|
|
|
|
if ((matrox_id == MATROX_MII_PCI_ID) ||
|
|
(matrox_id == MATROX_MII_AGP_ID))
|
|
cmd |= M_DWG_TRANSC;
|
|
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, cmd | mga_mix(af_fore_mix));
|
|
|
|
af_operation = OP_DRAWSLOWTRAP;
|
|
}
|
|
|
|
/* scan-convert the trapezoid */
|
|
while (trap->count--) {
|
|
ix1 = (trap->x1 + 0x8000) >> 16;
|
|
ix2 = (trap->x2 + 0x8000) >> 16;
|
|
|
|
if (ix2 < ix1) {
|
|
int tmp = ix1;
|
|
ix1 = ix2;
|
|
ix2 = tmp;
|
|
}
|
|
|
|
if (ix1 < ix2) {
|
|
mga_fifo(2);
|
|
mga_outl(M_FXBNDRY, (ix2 << 16) | ix1);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((trap->y + af_y) << 16) | 1);
|
|
}
|
|
|
|
trap->x1 += trap->slope1;
|
|
trap->x2 += trap->slope2;
|
|
trap->y++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* DrawTrap:
|
|
* Draws a filled trapezoid, using the current foreground mix mode.
|
|
*/
|
|
void DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap)
|
|
{
|
|
fixed startx1, startx2;
|
|
fixed endx1, endx2;
|
|
fixed tmp;
|
|
int dx1, dx2;
|
|
int sgn = 0;
|
|
|
|
mga_select( );
|
|
|
|
/* make the color a dword */
|
|
if (af_bpp == 8) {
|
|
color |= color << 8;
|
|
color |= color << 16;
|
|
} else if (af_bpp < 32) {
|
|
color |= color << 16;
|
|
}
|
|
|
|
mga_fifo(1);
|
|
mga_outl(M_FCOL, color);
|
|
|
|
/* read the edge coordinates */
|
|
startx1 = trap->x1;
|
|
startx2 = trap->x2;
|
|
|
|
endx1 = trap->x1 + trap->slope1 * trap->count;
|
|
endx2 = trap->x2 + trap->slope2 * trap->count;
|
|
|
|
if (startx1 > startx2) {
|
|
/* special case for when the edges cross */
|
|
if (endx1 < endx2) {
|
|
DrawSlowTrap(af, trap);
|
|
return;
|
|
}
|
|
|
|
/* make sure the left edge comes first */
|
|
tmp = startx1;
|
|
startx1 = startx2;
|
|
startx2 = tmp;
|
|
|
|
tmp = endx1;
|
|
endx1 = endx2;
|
|
endx2 = tmp;
|
|
|
|
trap->x1 = endx2;
|
|
trap->x2 = endx1;
|
|
} else {
|
|
trap->x1 = endx1;
|
|
trap->x2 = endx2;
|
|
}
|
|
|
|
/* calculate deltas */
|
|
dx1 = (endx1 - startx1) >> 16;
|
|
dx2 = (endx2 - startx2) >> 16;
|
|
|
|
startx1 = (startx1 + 0x8000) >> 16;
|
|
startx2 = (startx2 + 0x8000) >> 16;
|
|
|
|
if (dx1 < 0) sgn |= M_SDXL;
|
|
|
|
if (dx2 < 0) sgn |= M_SDXR;
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_DRAWTRAP) {
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, M_DWG_TRAP | M_DWG_SOLID | M_DWG_SHIFTZERO |
|
|
mga_mix(af_fore_mix));
|
|
|
|
af_operation = OP_DRAWTRAP;
|
|
}
|
|
|
|
/* draw the trapezoid */
|
|
mga_fifo(9);
|
|
mga_outl(M_AR0, trap->count);
|
|
mga_outl(M_AR1, (dx1 < 0) ? dx1 + trap->count - 1 : -dx1);
|
|
mga_outl(M_AR2, -ABS(dx1));
|
|
mga_outl(M_AR4, (dx2 < 0) ? dx2 + trap->count - 1 : -dx2);
|
|
mga_outl(M_AR5, -ABS(dx2));
|
|
mga_outl(M_AR6, trap->count);
|
|
mga_outl(M_SGN, sgn);
|
|
mga_outl(M_FXBNDRY, (startx2 << 16) | startx1);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((trap->y + af_y) << 16) | trap->count);
|
|
|
|
trap->y += trap->count;
|
|
trap->count = 0;
|
|
}
|
|
|
|
|
|
|
|
/* PutMonoImage:
|
|
* Expands a monochrome bitmap from system memory onto the screen.
|
|
*/
|
|
void PutMonoImage(AF_DRIVER *af, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, unsigned char *image)
|
|
{
|
|
unsigned long val;
|
|
int i, n, x, y;
|
|
long cmd;
|
|
int op;
|
|
|
|
mga_select( );
|
|
|
|
/* is the source data in linear format? */
|
|
if ((srcX > 0) || (width != byteWidth * 8))
|
|
op = OP_PUTMONOIMAGE_SLOW;
|
|
else
|
|
op = OP_PUTMONOIMAGE_LINEAR;
|
|
|
|
/* set engine state */
|
|
if (af_operation != op) {
|
|
cmd = M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF;
|
|
|
|
if (op == OP_PUTMONOIMAGE_LINEAR) cmd |= M_DWG_LINEAR;
|
|
|
|
if (af_back_mix == AF_NOP_MIX)
|
|
cmd |= mga_mix(af_fore_mix) | M_DWG_TRANSC;
|
|
else
|
|
cmd |= mga_mix_noblk(af_fore_mix);
|
|
|
|
mga_fifo(1);
|
|
mga_outl(M_DWGCTL, cmd);
|
|
|
|
af_operation = op;
|
|
}
|
|
|
|
/* make the color a dword */
|
|
if (af_bpp == 8) {
|
|
foreColor |= foreColor << 8;
|
|
foreColor |= foreColor << 16;
|
|
} else if (af_bpp < 32) {
|
|
foreColor |= foreColor << 16;
|
|
}
|
|
|
|
/* sort out the background color */
|
|
if (af_back_mix == AF_NOP_MIX) {
|
|
backColor = 0;
|
|
} else {
|
|
if (af_bpp == 8) {
|
|
backColor |= backColor << 8;
|
|
backColor |= backColor << 16;
|
|
} else if (af_bpp < 32) {
|
|
backColor |= backColor << 16;
|
|
}
|
|
}
|
|
|
|
/* skip leading image data */
|
|
image += srcY * byteWidth;
|
|
|
|
/* start the hardware engine */
|
|
mga_fifo(6);
|
|
mga_outl(M_FCOL, foreColor);
|
|
mga_outl(M_BCOL, backColor);
|
|
mga_outl(M_AR0,
|
|
(op == OP_PUTMONOIMAGE_LINEAR) ? width * height - 1 : width - 1);
|
|
mga_outl(M_AR3, 0);
|
|
mga_outl(M_FXBNDRY, ((dstX + width - 1) << 16) | dstX);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((dstY + af_y) << 16) | height);
|
|
|
|
if (op == OP_PUTMONOIMAGE_LINEAR) {
|
|
/* block copy to the psuedo-dma window */
|
|
n = (width * height + 31) / 32;
|
|
|
|
while (n > 0) {
|
|
i = MIN(n, 1792);
|
|
n -= i;
|
|
|
|
#ifdef NO_HWPTR
|
|
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(i), "S"(image), "D"(af->IOMemMaps[0])
|
|
|
|
: "%ecx", "%esi", "%edi");
|
|
|
|
#else
|
|
|
|
asm(" movw %%es, %%dx ; "
|
|
" movw %%ax, %%es ; "
|
|
" rep ; movsl ; "
|
|
" movw %%dx, %%es "
|
|
:
|
|
: "c"(i), "S"(image), "D"(hwptr.IOMemMaps[0].offset),
|
|
"a"(hwptr.IOMemMaps[0].sel)
|
|
|
|
: "%ecx", "%edx", "%esi", "%edi");
|
|
|
|
#endif
|
|
}
|
|
} else {
|
|
/* special munging is required when the source isn't linear */
|
|
for (y = 0; y < height; y++) {
|
|
val = 0;
|
|
i = 0;
|
|
|
|
for (x = 0; x < width; x++) {
|
|
val <<= 1;
|
|
if (image[(srcX + x) / 8] & (0x80 >> ((srcX + x) & 7)))
|
|
val |= 1;
|
|
|
|
if (i == 31) {
|
|
mga_outl(0, bswap(val));
|
|
val = 0;
|
|
i = 0;
|
|
} else
|
|
i++;
|
|
}
|
|
|
|
if (i) mga_outl(0, bswap(val << (32 - i)));
|
|
|
|
image += byteWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* BitBlt:
|
|
* Blits from one part of video memory to another, using the specified
|
|
* mix operation. This must correctly handle the case where the two
|
|
* regions overlap.
|
|
*/
|
|
void BitBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op)
|
|
{
|
|
int start, end;
|
|
int operation;
|
|
|
|
mga_select( );
|
|
|
|
/* which direction to copy? */
|
|
if ((left + width > dstLeft) && (top + height > dstTop) &&
|
|
(dstLeft + width > left) && (dstTop + height > top) &&
|
|
((dstTop > top) || ((dstTop == top) && (dstLeft > left))))
|
|
operation = OP_BITBLT_BACKWARD;
|
|
else
|
|
operation = OP_BITBLT_FORWARD;
|
|
|
|
/* set engine state */
|
|
if (af_operation != operation) {
|
|
if (operation == OP_BITBLT_FORWARD) {
|
|
mga_fifo(2);
|
|
mga_outl(M_AR5, af_width_pixels);
|
|
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
|
M_DWG_BFCOL | mga_mix_noblk(op));
|
|
} else {
|
|
mga_fifo(3);
|
|
mga_outl(M_SGN, 5);
|
|
mga_outl(M_AR5, -af_width_pixels);
|
|
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL |
|
|
mga_mix_noblk(op));
|
|
}
|
|
|
|
af_operation = operation;
|
|
}
|
|
|
|
/* adjust parameters */
|
|
if (operation == OP_BITBLT_BACKWARD) {
|
|
width--;
|
|
end = (top + af_y + height - 1) * af_width_pixels + left;
|
|
start = end + width;
|
|
dstTop += height - 1;
|
|
} else {
|
|
width--;
|
|
start = (top + af_y) * af_width_pixels + left;
|
|
end = start + width;
|
|
}
|
|
|
|
/* do the blit */
|
|
mga_fifo(4);
|
|
mga_outl(M_AR0, end);
|
|
mga_outl(M_AR3, start);
|
|
mga_outl(M_FXBNDRY, ((dstLeft + width) << 16) | dstLeft);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((dstTop + af_y) << 16) | height);
|
|
}
|
|
|
|
|
|
|
|
/* BitBltSys:
|
|
* Copies from system memory to the screen.
|
|
*/
|
|
void BitBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op)
|
|
{
|
|
int i, n;
|
|
void *addr;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_BITBLTSYS) {
|
|
mga_fifo(2);
|
|
mga_outl(M_AR5, 0);
|
|
mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
|
M_DWG_BFCOL | mga_mix_noblk(op));
|
|
|
|
af_operation = OP_BITBLTSYS;
|
|
}
|
|
|
|
/* adjust source bitmap pointers */
|
|
switch (af_bpp) {
|
|
case 8:
|
|
addr = srcAddr + srcLeft + srcTop * srcPitch;
|
|
n = (width + 3) / 4;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
addr = srcAddr + srcLeft * 2 + srcTop * srcPitch;
|
|
n = (width + 1) / 2;
|
|
break;
|
|
|
|
case 32:
|
|
addr = srcAddr + srcLeft * 4 + srcTop * srcPitch;
|
|
n = width;
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
/* wake up the hardware engine */
|
|
mga_fifo(4);
|
|
mga_outl(M_AR0, width - 1);
|
|
mga_outl(M_AR3, 0);
|
|
mga_outl(M_FXBNDRY, ((dstLeft + width - 1) << 16) | dstLeft);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((dstTop + af_y) << 16) | height);
|
|
|
|
/* copy data to the psuedo-dma window */
|
|
for (i = 0; i < height; i++) {
|
|
|
|
#ifdef NO_HWPTR
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(af->IOMemMaps[0])
|
|
|
|
: "%ecx", "%esi", "%edi");
|
|
|
|
#else
|
|
asm(" movw %%es, %%dx ; "
|
|
" movw %%ax, %%es ; "
|
|
" rep ; movsl ; "
|
|
" movw %%dx, %%es "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(hwptr.IOMemMaps[0].offset),
|
|
"a"(hwptr.IOMemMaps[0].sel)
|
|
|
|
: "%ecx", "%edx", "%esi", "%edi");
|
|
|
|
#endif
|
|
|
|
addr += srcPitch;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SrcTransBlt:
|
|
* Blits from one part of video memory to another, using the specified
|
|
* mix operation and skipping any source pixels which match the specified
|
|
* transparent color. Results are undefined if the two regions overlap.
|
|
*/
|
|
void SrcTransBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent)
|
|
{
|
|
int start, end;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_SRCTRANSBLT) {
|
|
if (af_bpp == 8) {
|
|
transparent |= transparent << 8;
|
|
transparent |= transparent << 16;
|
|
} else if (af_bpp < 32) {
|
|
transparent |= transparent << 16;
|
|
}
|
|
|
|
mga_fifo(4);
|
|
mga_outl(M_FCOL, transparent);
|
|
mga_outl(M_BCOL, 0xFFFFFFFF);
|
|
mga_outl(M_AR5, af_width_pixels);
|
|
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
|
M_DWG_BFCOL | M_DWG_TRANSC | mga_mix_noblk(op));
|
|
|
|
af_operation = OP_SRCTRANSBLT;
|
|
}
|
|
|
|
/* adjust parameters */
|
|
width--;
|
|
start = (top + af_y) * af_width_pixels + left;
|
|
end = start + width;
|
|
|
|
/* do the blit */
|
|
mga_fifo(4);
|
|
mga_outl(M_AR0, end);
|
|
mga_outl(M_AR3, start);
|
|
mga_outl(M_FXBNDRY, ((dstLeft + width) << 16) | dstLeft);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((dstTop + af_y) << 16) | height);
|
|
}
|
|
|
|
|
|
|
|
/* SrcTransBltSys:
|
|
* Copies from system memory to the screen, skipping any source pixels that
|
|
* match the specified transparent color.
|
|
*/
|
|
void SrcTransBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent)
|
|
{
|
|
int i, n;
|
|
void *addr;
|
|
|
|
mga_select( );
|
|
|
|
/* set engine state */
|
|
if (af_operation != OP_SRCTRANSBLTSYS) {
|
|
if (af_bpp == 8) {
|
|
transparent |= transparent << 8;
|
|
transparent |= transparent << 16;
|
|
} else if (af_bpp < 32) {
|
|
transparent |= transparent << 16;
|
|
}
|
|
|
|
mga_fifo(4);
|
|
mga_outl(M_FCOL, transparent);
|
|
mga_outl(M_BCOL, 0xFFFFFFFF);
|
|
mga_outl(M_AR5, 0);
|
|
mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
|
|
M_DWG_BFCOL | M_DWG_TRANSC | mga_mix_noblk(op));
|
|
|
|
af_operation = OP_SRCTRANSBLTSYS;
|
|
}
|
|
|
|
/* adjust source bitmap pointers */
|
|
switch (af_bpp) {
|
|
case 8:
|
|
addr = srcAddr + srcLeft + srcTop * srcPitch;
|
|
n = (width + 3) / 4;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
addr = srcAddr + srcLeft * 2 + srcTop * srcPitch;
|
|
n = (width + 1) / 2;
|
|
break;
|
|
|
|
case 32:
|
|
addr = srcAddr + srcLeft * 4 + srcTop * srcPitch;
|
|
n = width;
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
/* wake up the hardware engine */
|
|
mga_fifo(4);
|
|
mga_outl(M_AR0, width - 1);
|
|
mga_outl(M_AR3, 0);
|
|
mga_outl(M_FXBNDRY, ((dstLeft + width - 1) << 16) | dstLeft);
|
|
mga_outl(M_YDSTLEN | M_EXEC, ((dstTop + af_y) << 16) | height);
|
|
|
|
/* copy data to the psuedo-dma window */
|
|
for (i = 0; i < height; i++) {
|
|
|
|
#ifdef NO_HWPTR
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(af->IOMemMaps[0])
|
|
|
|
: "%ecx", "%esi", "%edi");
|
|
|
|
#else
|
|
asm(" movw %%es, %%dx ; "
|
|
" movw %%ax, %%es ; "
|
|
" rep ; movsl ; "
|
|
" movw %%dx, %%es "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(hwptr.IOMemMaps[0].offset),
|
|
"a"(hwptr.IOMemMaps[0].sel)
|
|
|
|
: "%ecx", "%edx", "%esi", "%edi");
|
|
|
|
#endif
|
|
|
|
addr += srcPitch;
|
|
}
|
|
}
|