/* * ______ ____ ______ _____ ______ * | ____| | _ \| ____| / / _ \| ____| * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __| * | | | | | __/ __/ |_) | |____ / / | | | | | * |_| |_| \___|\___|____/|______/_/ |_| |_|_| * * * Accelerated Matrox driver, by Shawn Hargreaves. * * See freebe.txt for copyright information. */ // #define NO_HWPTR #include #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 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; } }