diff --git a/ati/driver.c b/ati/driver.c
new file mode 100644
index 0000000..6a56780
--- /dev/null
+++ b/ati/driver.c
@@ -0,0 +1,620 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * ATI 18800/28800 driver (based on the Allegro ATI code).
+ *
+ * By Shawn Hargreaves.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+// #define NO_HWPTR
+
+
+#include
+
+#include "vbeaf.h"
+
+
+
+/* chipset information */
+#define ATI_18800 1
+#define ATI_18800_1 2
+#define ATI_28800_2 3
+#define ATI_28800_4 4
+#define ATI_28800_5 5
+
+int ati_type;
+
+int ati_port = 0x1CE;
+
+
+
+/* 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);
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+} VIDEO_MODE;
+
+
+VIDEO_MODE mode_list[] =
+{
+ { 640, 400, 8, 0x61 },
+ { 640, 480, 8, 0x62 }
+};
+
+
+#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_modes[NUM_MODES+1] = { 1, 2, -1 };
+
+
+
+/* detect:
+ * Detects the presence of an ATI card.
+ */
+char *detect()
+{
+ char *name = NULL;
+ char buf[16];
+ int sel, i;
+
+ sel = allocate_selector(0, 1024*1024);
+ if (sel < 0)
+ return NULL;
+
+ for (i=0; i<9; i++) /* check ID string */
+ buf[i] = _farpeekb(sel, 0xC0031+i);
+
+ if (memcmp(buf, "761295520", 9) != 0) {
+ free_selector(sel);
+ return NULL;
+ }
+
+ ati_port = _farpeekw(sel, 0xC0010); /* read port address */
+ if (!ati_port)
+ ati_port = 0x1CE;
+
+ switch (_farpeekb(sel, 0xC0043)) { /* check ATI type */
+
+ case '1':
+ ati_type = ATI_18800;
+ name = "18800";
+ break;
+
+ case '2':
+ ati_type = ATI_18800_1;
+ name = "18800-1";
+ break;
+
+ case '3':
+ ati_type = ATI_28800_2;
+ name = "28800-2";
+ break;
+
+ case '4':
+ ati_type = ATI_28800_4;
+ name = "28800-4";
+ break;
+
+ case '5':
+ ati_type = ATI_28800_5;
+ name = "28800-5";
+ break;
+
+ default:
+ /* unknown sort of ATI */
+ free_selector(sel);
+ return NULL;
+ }
+
+ free_selector(sel);
+
+ return name;
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ char *name;
+ int vram_size;
+ int i;
+
+ name = detect();
+
+ if (!name)
+ return 1;
+
+ i = 0;
+ while (af->OemVendorName[i])
+ i++;
+
+ af->OemVendorName[i++] = ',';
+ af->OemVendorName[i++] = ' ';
+
+ while (*name)
+ af->OemVendorName[i++] = *(name++);
+
+ af->OemVendorName[i] = 0;
+
+ if (get_vesa_info(&vram_size, NULL, NULL) != 0)
+ af->TotalMemory = 512;
+ else
+ af->TotalMemory = MIN(vram_size/1024, 512);
+
+ af->AvailableModes = available_modes;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ 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;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ long available_vram;
+ long used_vram;
+ int width;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo, linear framebuffer, or noclear */
+ if (mode & 0xC400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > NUM_MODES))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ /* call BIOS to set the mode */
+ r.x.ax = info->num;
+ rm_int(0x10, &r);
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX > info->w) {
+ if (virtualX > 1024)
+ return -1;
+
+ *bytesPerLine = ((virtualX*BYTES_PER_PIXEL(info->bpp))+15)&0xFFF0;
+
+ width = read_vga_register(0x3D4, 0x13);
+ write_vga_register(0x3D4, 0x13, (width * (*bytesPerLine)) / (info->w*BYTES_PER_PIXEL(info->bpp)));
+ }
+ else
+ *bytesPerLine = info->w*BYTES_PER_PIXEL(info->bpp);
+
+ /* set up some hardware registers */
+ if (ati_type >= ATI_28800_4) /* allow display past 512k */
+ alter_vga_register(ati_port, 0xB6, 1, 1);
+
+ if (ati_type >= ATI_18800_1) /* select single bank mode */
+ alter_vga_register(ati_port, 0xBE, 8, 0);
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* write high bits to ATI-specific registers */
+ if (ati_type < ATI_28800_2) {
+ alter_vga_register(ati_port, 0xB0, 0xC0, a>>12);
+ }
+ else {
+ alter_vga_register(ati_port, 0xB0, 0x40, a>>12);
+ alter_vga_register(ati_port, 0xA3, 0x10, a>>15);
+ }
+
+ /* write to normal VGA address registers */
+ write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
+ write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
+
+ asm volatile ("sti");
+
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i
+
+#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 WaitTillIdle(AF_DRIVER *af);
+void SetMix(AF_DRIVER *af, long foreMix, long backMix);
+
+
+/* if you need some video memory for internal use by the accelerator
+ * code (for example storing pattern data), you can define this value to
+ * reserve room for yourself at the very end of the memory space, that
+ * the application will not be allowed to use.
+ */
+#define RESERVED_VRAM 0
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_linear;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+int af_fore_mix;
+int af_back_mix;
+int af_lines_per_bank;
+
+
+/* note about VBE/AF multiple page modes: the API supports any number of
+ * video memory pages, one of which is "active" (being drawn onto), while
+ * the other is visible on your monitor. Allegro doesn't actually use
+ * this functionality, so you may safely leave it out and just reject
+ * any mode set requests with a numBuffers value greater than one, but
+ * that might upset other VBE/AF applications if they depend on this
+ * functionality. To support multiple pages, you must offset all the
+ * hardware drawing operations so their coordinate system is relative
+ * to the active page. You must also maintain an offset from the start
+ * of vram to the start of the active page in the OriginOffset of the
+ * driver structure, and adjust the OffscreenStartY and OffscreenEndY
+ * values so they will refer to the same offscreen memory region regardless
+ * of the current accelerator coordinate system. This is all handled by the
+ * SetActiveBuffer() function below, so in practice you can simply add
+ * af_active_page*af_height onto the input Y coordinate of any accelerator
+ * drawing funcs, and multiple page modes should work correctly.
+ */
+
+
+
+#define ALG_NONE 0
+#define ALG_2101 1
+#define ALG_2201 2
+#define ALG_2228 3
+#define ALG_2301 4
+#define ALG_UNKNOWN 5
+
+int port_crtc = 0x3d4;
+int port_attr = 0x3c0;
+int port_seq = 0x3c4;
+int port_grc = 0x3ce;
+
+int alg_version = ALG_NONE, alg_vidmem = 0;
+
+char *alg_name[6] = {
+ "none", "ALG-2101", "ALG-2201", "ALG-2228", "ALG-2301", "unknown"
+};
+
+int alg_caps[6] = {
+ 0,
+ afHaveMultiBuffer | afHaveBankedBuffer | afHaveVirtualScroll /*| afHaveDualBuffers */,
+ afHaveMultiBuffer | afHaveBankedBuffer | afHaveVirtualScroll /*| afHaveDualBuffers */,
+ afHaveMultiBuffer | afHaveBankedBuffer | afHaveVirtualScroll /*| afHaveDualBuffers */,
+ afHaveMultiBuffer | afHaveBankedBuffer | afHaveVirtualScroll /*| afHaveDualBuffers */,
+ 0
+};
+
+struct mode_t {
+ int mode;
+ int w,h;
+ int bpp;
+};
+
+#define MAX_MODES 20
+
+struct mode_t mode_list[] = {
+ /* mode width height bpp */
+ { 0x28, 512, 512, 8 },
+ { 0x29, 640, 400, 8 },
+ { 0x2a, 640, 480, 8 },
+ { 0x2c, 800, 600, 8 },
+ { 0x2e, 768, 1024, 8 },
+ { 0x31, 1024, 768, 8 },
+ { 0x33, 1024, 1024, 8 },
+ { 0x37, 1280, 1024, 8 },
+
+ { 0x40, 320, 200, 16 },
+ { 0x41, 512, 512, 16 },
+ { 0x42, 640, 400, 16 },
+ { 0x43, 640, 480, 16 },
+ { 0x44, 800, 600, 16 },
+ { 0x45, 1024, 768, 16 },
+
+ { 0x48, 640, 480, 24 },
+ { 0x49, 800, 600, 24 },
+
+ { 0, 0, 0, 0 }
+};
+
+short available_modes[MAX_MODES] = { -1 };
+
+
+static inline void clrinx (int pt, int inx, int val)
+{
+ write_vga_register (pt, inx, read_vga_register (pt, inx) & ~val);
+}
+
+static inline void setinx (int pt, int inx, int val)
+{
+ write_vga_register (pt, inx, read_vga_register (pt, inx) | val);
+}
+
+static inline void modinx (int pt, int inx, int mask, int nwv)
+{
+ write_vga_register (pt, inx, (read_vga_register (pt, inx) & ~mask) | (nwv & mask));
+}
+
+
+/* detect_alg:
+ * Sees whether or not an Avance Logic graphics card is present,
+ * and if one is it attempts to identify it.
+ */
+int detect_alg()
+{
+ int old;
+
+ alg_version = ALG_NONE;
+ alg_vidmem = 0;
+
+ old = read_vga_register (port_crtc, 0x1a);
+ clrinx (port_crtc, 0x1a, 0x10);
+ if (!test_vga_register (port_crtc, 0x19, 0xcf)) {
+ setinx (port_crtc, 0x1a, 0x10);
+ if (test_vga_register (port_crtc, 0x19, 0xcf) && test_vga_register (port_crtc, 0x1a, 0x3f)) {
+ int tmp = read_vga_register (port_crtc, 0x1a) >> 6;
+ switch (tmp) {
+ case 3:
+ alg_version = ALG_2101;
+ break;
+ case 2:
+ if (read_vga_register (port_crtc, 0x1b) & 4)
+ alg_version = ALG_2228;
+ else
+ alg_version = ALG_2301;
+ break;
+ case 1:
+ alg_version = ALG_2201;
+ default:
+ alg_version = ALG_UNKNOWN;
+ }
+ alg_vidmem = 256 << (read_vga_register (port_crtc, 0x1e) & 3);
+ }
+ }
+ write_vga_register (port_crtc, 0x1a, old);
+ return alg_version;
+}
+
+
+/* create_available_mode_list:
+ * Scans the mode list checking memory requirements. Modes
+ * which pass the test go into the available_modes list.
+ */
+void create_available_mode_list()
+{
+ struct mode_t *mode;
+ short *current_mode_in_list = available_modes;
+
+ for (mode = mode_list; mode->mode; mode++)
+ if (mode->w * mode->h * BYTES_PER_PIXEL (mode->bpp) < alg_vidmem * 1024)
+ *current_mode_in_list++ = mode->mode;
+
+ *current_mode_in_list = -1;
+}
+
+
+/* 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)
+{
+ int i;
+
+ if (!detect_alg()) return -1;
+
+ create_available_mode_list();
+
+ /* pointer to a list of the available mode numbers, ended by -1 */
+ af->AvailableModes = available_modes;
+
+ /* amount of video memory in K */
+ af->TotalMemory = alg_vidmem;
+
+ /* driver attributes (see definitions in vbeaf.h) */
+ af->Attributes = alg_caps[alg_version];
+
+ #if 0
+ if (linear_addr)
+ af->Attributes |= afHaveLinearBuffer;
+ #endif
+
+ /* banked memory size and location: zero if not supported */
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ /* linear framebuffer size and location: zero if not supported */
+ af->LinearSize = 0;
+ af->LinearBasePtr = 0;
+
+ /* list which ports we are going to access (only needed under Linux) */
+ af->IOPortsTable = ports_table;
+
+ /* list physical memory regions that we need to access (zero for none) */
+ for (i=0; i<4; i++) {
+ af->IOMemoryBase[i] = 0;
+ af->IOMemoryLen[i] = 0;
+ }
+
+ /* driver state variables (initialised later during the mode set) */
+ af->BufferEndX = 0;
+ af->BufferEndY = 0;
+ af->OriginOffset = 0;
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+
+ /* relocatable bank switcher (not required by Allgero) */
+ af->SetBank32 = SetBank32;
+ af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
+
+ /* extension functions */
+ af->SupplementalExt = ExtStub;
+
+ /* device driver functions */
+ 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->EnableStereoMode = NULL;
+ af->SetPaletteData = SetPaletteData;
+ af->SetGammaCorrectData = NULL;
+ af->SetBank = SetBank;
+
+ /* hardware cursor functions */
+ af->SetCursor = NULL;
+ af->SetCursorPos = NULL;
+ af->SetCursorColor = NULL;
+ af->ShowCursor = NULL;
+
+ /* wait until the accelerator hardware has finished drawing */
+ af->WaitTillIdle = WaitTillIdle;
+
+ /* on some cards the CPU cannot access the framebuffer while it is in
+ * hardware drawing mode. If this is the case, you should fill in these
+ * functions with routines to switch in and out of the accelerator mode.
+ * The application will call EnableDirectAccess() whenever it is about
+ * to write to the framebuffer directly, and DisableDirectAccess()
+ * before it calls any hardware drawing routines. If this arbitration is
+ * not required, leave these routines as NULL.
+ */
+ af->EnableDirectAccess = NULL;
+ af->DisableDirectAccess = NULL;
+
+ /* sets the hardware drawing mode (solid, XOR, etc). Required. */
+ af->SetMix = SetMix;
+
+ /* pattern download functions. May be NULL if patterns not supported */
+ af->Set8x8MonoPattern = NULL;
+ af->Set8x8ColorPattern = NULL;
+ af->Use8x8ColorPattern = NULL;
+
+ /* not supported: not used by Allegro */
+ af->SetLineStipple = NULL;
+ af->SetLineStippleCount = NULL;
+
+ /* not supported. There really isn't much point in this function because
+ * a lot of hardware can't do clipping at all, and even when it can there
+ * are usually problems with very large or negative coordinates. This
+ * means that a software clip is still required, so you may as well
+ * ignore this routine.
+ */
+ af->SetClipRect = NULL;
+
+ /* DrawScan() is required: patterned versions may be NULL */
+ af->DrawScan = NULL;
+ af->DrawPattScan = NULL;
+ af->DrawColorPattScan = NULL;
+
+ /* not supported: not used by Allegro */
+ af->DrawScanList = NULL;
+ af->DrawPattScanList = NULL;
+ af->DrawColorPattScanList = NULL;
+
+ /* rectangle filling: may be NULL */
+ af->DrawRect = NULL;
+ af->DrawPattRect = NULL;
+ af->DrawColorPattRect = NULL;
+
+ /* line drawing: may be NULL */
+ af->DrawLine = NULL;
+
+ /* not supported: not used by Allegro */
+ af->DrawStippleLine = NULL;
+
+ /* trapezoid filling: may be NULL */
+ af->DrawTrap = NULL;
+
+ /* not supported: not used by Allegro */
+ af->DrawTri = NULL;
+ af->DrawQuad = NULL;
+
+ /* monochrome character expansion: may be NULL */
+ af->PutMonoImage = NULL;
+
+ /* not supported: not used by Allegro */
+ af->PutMonoImageLin = NULL;
+ af->PutMonoImageBM = NULL;
+
+ /* opaque blitting: may be NULL */
+ af->BitBlt = NULL;
+ af->BitBltSys = NULL;
+
+ /* not supported: not used by Allegro */
+ af->BitBltLin = NULL;
+ af->BitBltBM = NULL;
+
+ /* masked blitting: may be NULL */
+ af->SrcTransBlt = NULL;
+ af->SrcTransBltSys = NULL;
+
+ /* not supported: not used by Allegro */
+ af->SrcTransBltLin = NULL;
+ af->SrcTransBltBM = NULL;
+ af->DstTransBlt = NULL;
+ af->DstTransBltSys = NULL;
+ af->DstTransBltLin = NULL;
+ af->DstTransBltBM = NULL;
+ af->StretchBlt = NULL;
+ af->StretchBltSys = NULL;
+ af->StretchBltLin = NULL;
+ af->StretchBltBM = NULL;
+ af->SrcTransStretchBlt = NULL;
+ af->SrcTransStretchBltSys = NULL;
+ af->SrcTransStretchBltLin = NULL;
+ af->SrcTransStretchBltBM = NULL;
+ af->DstTransStretchBlt = NULL;
+ af->DstTransStretchBltSys = NULL;
+ af->DstTransStretchBltLin = NULL;
+ af->DstTransStretchBltBM = NULL;
+ af->SetVideoInput = NULL;
+ af->SetVideoOutput = NULL;
+ af->StartVideoFrame = NULL;
+ af->EndVideoFrame = NULL;
+
+ 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)
+{
+ return 0;
+}
+
+
+
+/* FreeBEX:
+ * Returns an interface structure for the requested FreeBE/AF extension.
+ */
+void *FreeBEX(AF_DRIVER *af, unsigned long id)
+{
+ switch (id) {
+
+ default:
+ return NULL;
+ }
+}
+
+
+
+/* ExtStub:
+ * Vendor-specific extension hook: we don't provide any.
+ */
+int ExtStub()
+{
+ return 0;
+}
+
+
+/* findmode:
+ * Finds the given mode's entry in the mode list.
+ */
+struct mode_t *findmode (int mode)
+{
+ struct mode_t *ret;
+ for (ret = mode_list; ret->mode; ret++)
+ if (ret->mode == mode) return ret;
+ return NULL;
+}
+
+
+/* get_field_data:
+ * Fills in the mask size and position of each part of a pixel
+ * for the given colour depth.
+ */
+void get_field_data (int bpp, char *rm, char *rp, char *gm, char *gp, char *bm, char *bp, char *xm, char *xp)
+{
+ int pos = 0;
+
+ #define FIELD(xxx,size) *xxx##p = pos; pos += (*xxx##m = size)
+
+ switch (bpp) {
+ case 15:
+ FIELD (b, 5);
+ FIELD (g, 5);
+ FIELD (r, 5);
+ FIELD (x, 1);
+ break;
+ case 16:
+ FIELD (b, 5);
+ FIELD (g, 6);
+ FIELD (r, 5);
+ FIELD (x, 0);
+ break;
+ case 24:
+ FIELD (b, 8);
+ FIELD (g, 8);
+ FIELD (r, 8);
+ FIELD (x, 0);
+ break;
+ case 32:
+ FIELD (b, 8);
+ FIELD (g, 8);
+ FIELD (r, 8);
+ FIELD (x, 8);
+ break;
+ default:
+ FIELD (b, 0);
+ FIELD (g, 0);
+ FIELD (r, 0);
+ FIELD (x, 0);
+ }
+
+ #undef FIELD
+}
+
+
+/* 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)
+{
+ int i;
+ int bytes_per_scanline;
+ struct mode_t *info = findmode (mode);
+
+ if (!info) return -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 = alg_caps[alg_version];
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ bytes_per_scanline = info->w * BYTES_PER_PIXEL(info->bpp);
+
+ /* available pages of video memory */
+ modeInfo->MaxBuffers = (alg_vidmem * 1024 - RESERVED_VRAM) /
+ (bytes_per_scanline * info->h);
+
+ /* maximum virtual scanline length in both bytes and pixels. How wide
+ * this can go will very much depend on the card: 1024 is pretty safe
+ * on anything, but you will want to allow larger limits if the card
+ * is capable of them.
+ */
+ modeInfo->MaxScanLineWidth = 1024;
+ modeInfo->MaxBytesPerScanLine = modeInfo->MaxScanLineWidth*BYTES_PER_PIXEL(info->bpp);
+
+ /* for banked video modes, fill in these variables: */
+ modeInfo->BytesPerScanLine = bytes_per_scanline;
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ get_field_data (
+ info->bpp,
+ &modeInfo->RedMaskSize, &modeInfo->RedFieldPosition,
+ &modeInfo->GreenMaskSize, &modeInfo->GreenFieldPosition,
+ &modeInfo->BlueMaskSize, &modeInfo->BlueFieldPosition,
+ &modeInfo->RsvdMaskSize, &modeInfo->RsvdFieldPosition
+ );
+
+ /* for linear video modes, fill in these variables: */
+ modeInfo->LinBytesPerScanLine = bytes_per_scanline;
+ modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
+ modeInfo->LinRedMaskSize = modeInfo->RedMaskSize;
+ modeInfo->LinRedFieldPosition = modeInfo->RedFieldPosition;
+ modeInfo->LinGreenMaskSize = modeInfo->GreenMaskSize;
+ modeInfo->LinGreenFieldPosition = modeInfo->GreenFieldPosition;
+ modeInfo->LinBlueMaskSize = modeInfo->BlueMaskSize;
+ modeInfo->LinBlueFieldPosition = modeInfo->BlueFieldPosition;
+ modeInfo->LinRsvdMaskSize = modeInfo->RsvdMaskSize;
+ modeInfo->LinRsvdFieldPosition = modeInfo->RsvdFieldPosition;
+
+ /* 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;
+}
+
+
+/* setvstart:
+ * Sets the display start address.
+ */
+void setvstart (int x, int y)
+{
+ int addr = af_width * y + x * BYTES_PER_PIXEL (af_bpp);
+ int display, pixels;
+
+ if (read_vga_register (port_grc, 0x0c) & 0x10) {
+ display = addr >> 3;
+ pixels = addr & 7;
+ } else {
+ display = addr >> 2;
+ pixels = addr & 3;
+ }
+
+ write_vga_register (port_crtc, 0x20, (display >> 16) & 0x07);
+ write_vga_register (port_crtc, 0x0c, (display >> 8) & 0xff);
+ write_vga_register (port_crtc, 0x0d, display & 0xff);
+}
+
+
+/* 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)
+{
+ int linear = ((mode & 0x4000) != 0);
+ long available_vram;
+ long used_vram;
+ struct mode_t *info;
+ RM_REGS r;
+ int interlaced, word_mode, double_word_mode, _8maps, shift;
+
+ /* reject anything with hardware stereo */
+ if (mode & 0x400)
+ return -1;
+
+ /* mask off the other flag bits */
+ mode &= 0x3FF;
+
+ info = findmode (mode);
+ if (!info) return -1;
+
+ /* reject the linear flag if the mode doesn't support it */
+ if (linear) return -1;
+
+ /* set the mode */
+ r.x.ax = info->mode;
+ rm_int (0x10, &r);
+ if (r.h.ah) return -1;
+
+ setinx (port_crtc, 0x1A, 0x10); /* enable extensions */
+ setinx (port_crtc, 0x19, 0x02); /* enable >256k */
+ setinx (port_grc, 0x0F, 0x04); /* enable separate R/W banks */
+
+ af_bpp = info->bpp;
+
+ /* get some information about the mode */
+ interlaced = read_vga_register (port_crtc, 0x19) & 1;
+ double_word_mode = !!(read_vga_register (port_crtc, 0x14) & 0x40);
+ word_mode = !(read_vga_register (port_crtc, 0x17) & 0x40);
+ _8maps = !!(read_vga_register (0x3ce, 0x0c) & 0x10);
+
+ /* calculate the shift factor for the scanline byte width */
+ shift = 0;
+ if (_8maps) shift++;
+ if (double_word_mode)
+ shift += 3;
+ else if (word_mode)
+ shift += 2;
+ else
+ shift++;
+ if (interlaced) shift--;
+
+ /* sort out the virtaul screen size */
+ af_width = MAX (info->w, virtualX) * BYTES_PER_PIXEL (af_bpp);
+ af_width = (((af_width - 1) >> shift) + 1) << shift;
+
+ /* test: force it to be power of two */
+ {
+ int i = 1;
+ while (i < af_width) i <<= 1;
+ af_width = i;
+ }
+
+ /* Set scanline width */
+ write_vga_register (port_crtc, 0x13, af_width >> shift);
+ /* could also write bit 8 to port_crtc:0x28 bit 8 */
+
+ af_height = MAX (info->h, virtualY);
+
+ af_linear = linear;
+ af_lines_per_bank = af->BankSize * 1024 / af_width;
+ af_visible_page = 0;
+ af_active_page = 0;
+
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ setvstart (af_scroll_x, af_scroll_y);
+
+ af_bank = 0;
+
+ /* return framebuffer dimensions to the application */
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory * 1024 - RESERVED_VRAM;
+
+ if (used_vram > available_vram) return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ } else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ af_fore_mix = AF_REPLACE_MIX;
+ af_back_mix = AF_FORE_MIX;
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ af_scroll_x = x;
+ af_scroll_y = y;
+ if (waitVRT >= 0) setvstart (x, y);
+ if (waitVRT == 1) {
+ while (inportb (0x3da) & 8);
+ while (!(inportb (0x3da) & 8));
+ }
+}
+
+
+
+/* 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i
diff --git a/cirrus54/cirdefs.h b/cirrus54/cirdefs.h
new file mode 100644
index 0000000..4611a30
--- /dev/null
+++ b/cirrus54/cirdefs.h
@@ -0,0 +1,264 @@
+#ifndef CIR_DEFS_H
+#define CIR_DEFS_H
+
+#include
+
+typedef enum {
+ CLGD5426, //1
+ CLGD5428, //1
+ CLGD5429, //2
+ CLGD5430, //3
+ CLGD5434, //4
+ CLGD5434E, //5
+ CLGD5436, //6
+ CLGD5440, //7
+ CLGD5446, //8
+ CLGD5480, //9
+ CLGD7541, //10
+ CLGD7542, //11
+ CLGD7543, //10
+ CLGD7548, //12
+ CLGD7555, //13
+ CLGD7556 //13
+} cirrus_types;
+
+#define KNOWN_CARDS 16
+
+//54m30
+//54m40 - triple buffer, transparent color register
+/*
+1 - the oldest BitBLT capable chips, !!for color-expand with transparency
+transparent color is used !!, maxwidth 2047, maxpitch 4095, maxheight 1023,
+all BitBLT registers except src&dstaddr are preserved, allow at most 7 bits
+to be discarded with color expansion at the end of each scanline, color
+expansion and hw cursor in 8 and 15/16bpp supported
+2 - supports MMIO at b8000 or at the end of linear address space (2mb-256),
+!!for color-expand with transparency 0 bits are just skipped!!, maxpitch 8191, color expansion
+with left edge clipping&pattern vertical preset, supports color expanded
+pattern polygon fills
+3 - like 2, ? need srcaddr to be written for color expansion system to
+screen ?, hw cursor also at 24/32bpp
+4 - like 3, but 64 bit, maxwidth 8191, doesn't support clipping&vertical
+preset and polygon fills, color expansion in 32bpp supported, for color
+expansion with transparency all 4 bytes of fg color has to be written and 4
+bytes of color has to be filled with not fg color, has bug in system to
+display memory transfers, hw cursor also at 24/32bpp,
+5 - the bug is corrected
+6 - like 2, but 64 bit, maxwidth 8191, maxheight 2047,supports solid fill,
+color expansion in 24 and 32bpp, for 24bpp color expansion transparency must
+be enabled, but can invert the meaning of input data, so normal color
+expansion can de done in two passes, has auto-start capability, hw cursor
+also at 24/32bpp, triple buffer ?
+7 - like 3 with video features
+8 - like 9, no clipping, no X-Y pos.
+9 - like 6, has clip rectangle, X-Y positioning, command list with possible
+interrupt on completion, left edge clipping more complex, can probably triple
+buffer, color expand with uses transparent color, no transparent mask
+10 - (7541,7543) like 1, height is _not_ preserved
+11 - (7542) don't know anything
+12 - (7548) like 1 with MMIO, autostart, height is _not_ preserved
+13 - (7555-6) like 6, MMIO in PCI 0x14 or offset 0x3fff00, triple buffer
+ GR16-17, no 32bpp color expansion, autostart
+ if banked GR6[3:2]=01,SR17[6]=0,SR17[7:4]=0
+ else SR17[6]=1,SR17[7:4]!=0
+*/
+
+typedef struct {
+ cirrus_types model;
+ int biosnum,pcinum;
+ char *desc;
+ int family;
+} CIRRUS_DETECT;
+
+extern unsigned long af_mmio;
+
+#define GRX 0x3ce
+#define _crtc 0x3d4
+
+__inline__ void _vsync_out_h()
+{
+ do {
+ } while (inportb(0x3DA) & 1);
+}
+
+/* _vsync_out_v:
+ * Waits until the VGA is not in a vertical retrace.
+ */
+__inline__ void _vsync_out_v()
+{
+ do {
+ } while (inportb(0x3DA) & 8);
+}
+
+
+/* _vsync_in:
+ * Waits until the VGA is in the vertical retrace period.
+ */
+__inline__ void _vsync_in()
+{
+ do {
+ } while (!(inportb(0x3DA) & 8));
+}
+
+
+/* _write_hpp:
+ * Writes to the VGA pelpan register.
+ */
+__inline__ void _write_hpp(int value)
+{
+ write_vga_register(0x3C0, 0x33, value);
+}
+
+#define outm1(index, value) *(volatile char *)(af_mmio + index) = (value)
+#define outm2(index, value) *(volatile short *)(af_mmio + index) = (value)
+#define outm4(index, value) *(volatile long *)(af_mmio + index) = (value)
+#define inmb(index) *(volatile char *)(af_mmio + index)
+
+__inline__ void outp1(unsigned short port,unsigned char index,unsigned char value)
+{
+ unsigned short w;
+
+ w=index;
+ w|=value<<8;
+ outportw(port,w);
+}
+
+__inline__ void outp2(unsigned short port,unsigned char index,unsigned short value)
+{
+ unsigned short w;
+
+ w=index;
+ w|=((value&0xff)<<8);
+ outportw(port,w);
+ w=index+1;
+ w|=(value&0xff00);
+ outportw(port,w);
+}
+
+__inline__ void outp3(unsigned short port,unsigned char index,unsigned long value)
+{
+ unsigned short w;
+
+ w=index;
+ w|=(value&0xff)<<8;
+ outportw(port,w);
+ w=index+1;
+ w|=(value&0xff00);
+ outportw(port,w);
+ w=index+2;
+ w|=(value>>8)&0xff00;
+ outportw(port,w);
+}
+
+#define DISABLE() asm volatile ("cli");
+#define ENABLE() asm volatile ("sti");
+
+#define CIR_FORG8(color) outp1(GRX,0x01,(color))
+
+#define CIR_FORG16(color) outp1(GRX,0x01,(color) & 0xff); \
+ outp1(GRX,0x11,((color)>>8) & 0xff)
+#define CIR_FORG24(color) outp1(GRX,0x01,(color) & 0xff); \
+ outp1(GRX,0x11,((color)>>8) & 0xff); \
+ outp1(GRX,0x13,((color)>>16) & 0xff)
+#define CIR_FORG32(color) outp1(GRX,0x01,(color) & 0xff); \
+ outp1(GRX,0x11,((color)>>8) & 0xff); \
+ outp1(GRX,0x13,((color)>>16) & 0xff); \
+ outp1(GRX,0x15,((color)>>24) & 0xff)
+
+#define CIR_BACKG8(color) outp1(GRX,0x00,(color))
+#define CIR_BACKG16(color) outp1(GRX,0x00,(color) & 0xff); \
+ outp1(GRX,0x10,((color)>>8) & 0xff)
+#define CIR_BACKG24(color) outp1(GRX,0x00,(color) & 0xff); \
+ outp1(GRX,0x10,((color)>>8) & 0xff); \
+ outp1(GRX,0x12,((color)>>16) & 0xff)
+#define CIR_BACKG32(color) outp1(GRX,0x00,(color) & 0xff); \
+ outp1(GRX,0x10,((color)>>8) & 0xff); \
+ outp1(GRX,0x12,((color)>>16) & 0xff); \
+ outp1(GRX,0x14,((color)>>24) & 0xff)
+
+#define CIR_FORG8MMIO(color) outm1(0x04,(color))
+#define CIR_FORG16MMIO(color) outm2(0x04,(color))
+#define CIR_FORG24MMIO(color) outm4(0x04,(color))
+#define CIR_FORG32MMIO(color) outm4(0x04,(color))
+
+#define CIR_BACKG8MMIO(color) outm1(0x00,(color))
+#define CIR_BACKG16MMIO(color) outm2(0x00,(color))
+#define CIR_BACKG24MMIO(color) outm4(0x00,(color))
+#define CIR_BACKG32MMIO(color) outm4(0x00,(color))
+
+#define SET_WIDTH_HEIGHTMMIO(width,height) outm4(0x08,(width)|(((height)<<16)))
+
+#define SET_PITCHESMMIO(src,dst) outm4(0x0c,(dst)|((src)<<16)
+
+#define SET_DSTADDRMMIO(address) outm4(0x10,address)
+
+/* in last byte of is left edge clipping - to be added */
+#define SET_SRCADDRMMIO(address) outm4(0x14,address)
+
+#define CIR_ROP_MODEMMIO(rop,mode) outm4(0x18,(mode)|((rop)<<16))
+
+#define CIR_BLTROPMMIO(rop) outm1(0x1a,rop)
+#define CIR_BLTMODEMMIO(mode) outm1(0x18,mode)
+
+#define CIR_WIDTH(width) outp2(GRX,0x20,width)
+#define CIR_HEIGHT(height) outp2(GRX,0x22,height)
+#define CIR_DSTPITCH(pitch) outp2(GRX,0x24,pitch)
+#define CIR_SRCPITCH(pitch) outp2(GRX,0x26,pitch)
+#define SET_DSTADDR(address) outp3(GRX,0x28,address)
+#define SET_SRCADDR(address) outp3(GRX,0x2c,address)
+#define CIR_BLTMODE(mode) outp1(GRX,0x30,mode)
+#define CIR_BLTROP(rop) outp1(GRX,0x32,rop)
+#define CIR_TRANS(color) outp2(GRX,0x34,(color)); \
+ outp2(GRX,0x38,0);
+#define CIR_TRANSMMIO(color) outm2(0x34,(color))
+
+#define CIR_CMD(cmd) outp1(GRX,0x31,cmd)
+
+
+#define CIR_CMDMMIO(cmd) outm1(0x40,cmd)
+
+#define CIR_BLT_PIX8 0
+#define CIR_BLT_PIX15 16
+#define CIR_BLT_PIX16 16
+#define CIR_BLT_PIX24 32
+#define CIR_BLT_PIX32 48
+
+#define CIR_ROP_COPY 0x0d
+#define CIR_ROP_XOR 0x59
+#define CIR_ROP_AND 0x05
+#define CIR_ROP_OR 0x6d
+#define CIR_ROP_NOP 0x00
+
+#define CIR_CMD_RUN 0x02
+#define CIR_CMD_BUSY 0x01
+#define CIR_BLT_BACK 0x01
+#define CIR_BLT_TRANS 0x08
+#define CIR_BLT_PATT 0x40
+#define CIR_BLT_MEM 0x04
+#define CIR_BLT_COLEXP 0x80
+
+#define my_int(num,regs) asm("\
+pushal; \
+pushl %%esi; \
+movl (%%esi),%%edi; \
+movl 8(%%esi),%%ebp; \
+movl 16(%%esi),%%ebx;\
+movl 20(%%esi),%%edx;\
+movl 24(%%esi),%%ecx;\
+movl 28(%%esi),%%eax;\
+pushl 4(%%esi); \
+popl %%esi; \
+int %1; \
+xchgl %%esi,(%%esp); \
+movl %%eax,28(%%esi);\
+movl %%ecx,24(%%esi);\
+movl %%edx,20(%%esi);\
+movl %%ebx,16(%%esi);\
+movl %%ebp,8(%%esi); \
+movl %%edi,(%%esi); \
+popl %%eax; \
+movl %%eax,4(%%esi); \
+popal" \
+ ::"S" (regs), "i" (num))
+
+#endif
diff --git a/cirrus54/driver.c b/cirrus54/driver.c
new file mode 100644
index 0000000..82f22a1
--- /dev/null
+++ b/cirrus54/driver.c
@@ -0,0 +1,2017 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Cirrus54xx (not 546x) driver
+ *
+ * See freebe.txt for copyright information.
+ */
+
+#include
+
+#include "vbeaf.h"
+#include "cirdefs.h"
+
+/******************************************************************************/
+/* If you are having trouble getting this driver to work, try uncommenting */
+/* the line below to disable memory-mapped IO. Also, read NOTES.TXT. */
+/******************************************************************************/
+//#define DISABLE_MMIO
+
+//#define NO_CACHE //the values in registers BitBLT doesn't changed won't be cached
+
+/* 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 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);
+
+/* if you need some video memory for internal use by the accelerator
+ * code (for example storing pattern data), you can define this value to
+ * reserve room for yourself at the very end of the memory space, that
+ * the application will not be allowed to use.
+ */
+#define RESERVED_VRAM 2048
+
+//last 256 bytes can be used by MMIO on 5429, so I reserve them for sure
+
+#define MONOPATTSTART 1024
+#define SOLIDPATTSTART 768
+#define COLPATTSTART 512
+#define CURSORSTART 2048
+#define DISPLACEMENT 0x10000
+#define CIRRUS_PCI_VENDOR_ID 0x1013
+
+CIRRUS_DETECT detect_info[]={
+{ CLGD5426, 0x15, 0, "CLGD-5426", 0 },
+{ CLGD5428, 0x18, 0, "CLGD-5428", 0 },
+{ CLGD5429, 0x19, 0, "CLGD-5429", 1 },
+{ CLGD5430, 0x32, 0xa0, "CLGD-5430", 2 },
+{ CLGD5434, 0x31, 0xa4, "CLGD-5434", 3 },
+{ CLGD5434E, 0x33, 0xa8, "CLGD-5434 rev E",4 },
+{ CLGD5436, 0x36, 0xac, "CLGD-5436",5 },
+{ CLGD5440, 0x32, 0xa0, "CLGD-5440",2 },//find by reading chip id register 0xb0
+{ CLGD5446, 0x39, 0xb8, "CLGD-5446",5 },
+{ CLGD5480, 0x3a, 0xbc, "CLGD-5480",6 },
+{ CLGD7541, 0x41, 0x1204, "CLGD-7541",7 },
+{ CLGD7542, 0x43, 0x1200, "CLGD-7542",-1 },
+{ CLGD7543, 0x42, 0x1202, "CLGD-7543",7 },
+{ CLGD7548, 0x44, 0x38, "CLGD-7548",-1 },
+{ CLGD7555, 0x46, 0, "CLGD-7555",-1 },
+{ CLGD7556, 0x47, 0, "CLGD-7556",-1 }
+};
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0x3c0,0x3c4,0x3ce,0x3d4,0x3da,0xFFFF };
+
+typedef struct _GFX_MODE_INFO
+{
+ int w, h;
+ int bpp;
+ int bpl;
+ int num;
+// int tweak; //index to height modifiing table (substract 1 to get real index)
+} _GFX_MODE_INFO;
+
+#define MAX_MODES 25
+
+_GFX_MODE_INFO mode_list[] =
+{
+ { 640, 400, 8, 640, 0x5E},
+ { 640, 480, 8, 640, 0x5F},
+ { 800, 600, 8, 800, 0x5C},
+ { 1024, 768, 8, 1024, 0x60},
+ { 1280, 1024, 8, 1280, 0x6D},
+ { 1600, 1200, 8, 1600, 0x78},
+ { 640, 480, 15, 1280, 0x66},
+ { 800, 600, 15, 1600, 0x67},
+ { 1024, 768, 15, 2048, 0x68},
+ { 1280, 1024, 15, 2560, 0x69},
+ { 320, 200, 16, 640, 0x6F},
+ { 640, 480, 16, 1280, 0x64},
+ { 800, 600, 16, 1600, 0x65},
+ { 1024, 768, 16, 2048, 0x74},
+ { 1280, 1024, 16, 2560, 0x75},
+ { 320, 200, 24, 960, 0x70},
+ { 640, 480, 24, 2048, 0x71},
+ { 1280, 1024, 24, 3840, 0x77},
+ { 640, 480, 32, 2560, 0x76},
+ { 800, 600, 32, 3200, 0x72},
+ { 1024, 768, 32, 4096, 0x73},
+ { 1152, 870, 32, 4608, 0x79},
+ { 0, 0, 0, 0, 0}
+};
+
+int cir_maxpitch = 0;
+int cir_useblt24 = 0;
+int cir_useblt32 = 0;
+int cir_offmono = 0; //linear address in VRAM where mono pattern starts
+int cir_offscreen = 0;//linear address in VRAM where full pattern starts (solid fills)
+int cir_offcolor = 0; //linear address in VRAM where color pattern starts
+int cir_bpp = 0;
+int cir_bltmode = 0;
+int cir_bltrop = 0;
+int cir_pixmode = 0;
+int cir_maxheight = 0;
+int cir_maxwidth = 0;
+int mouse_fg = 0;
+int cir_cursor_visible = 0;
+
+/* old values (used for caching) */
+int cir_fg = -1;
+int cir_bg = -1;
+int cir_trans = -1;
+int cir_oldbltmode = -1;
+int cir_oldbltrop = -1;
+int cir_height = -1;
+int cir_card = -1;
+int need_wait = 0;
+unsigned long linear_addr = 0;
+
+short available_modes[MAX_MODES+1] = { -1 };
+short num_modes=-1;
+
+/* internal driver state variables */
+int af_bpp;
+int af_bank;
+int af_width;
+int af_height;
+int af_linear;
+unsigned long af_mmio=0;
+int af_visible_page;
+int af_active_page;
+int af_last_bank;
+int af_fore_mix;
+int af_back_mix;
+int af_memory;
+
+
+/* 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 b = x * cir_bpp + (y+af_visible_page*af_height) * af_width;
+ long a=b>>2;
+ long t;
+
+
+ af->WaitTillIdle(af);
+
+ DISABLE();
+ if (waitVRT) {
+ _vsync_out_h();
+ }
+ /* write high bits to Cirrus 54xx registers */
+ t = (a >> 16)&1; //bit 16
+ t +=(a >> 15)&12; /* funny format, uses bits 0, 2, and 3 */
+ alter_vga_register(_crtc, 0x1B, 0xD, t);
+ alter_vga_register(_crtc,0x1D,0x80,(a>>11)&0x80);
+ /* write to normal VGA address registers */
+ write_vga_register(_crtc, 0x0D, (a) & 0xFF);
+ write_vga_register(_crtc, 0x0C, (a>>8) & 0xFF);
+
+ ENABLE();
+ /* write low 2 bits to VGA horizontal pan register */
+ _write_hpp(b&3);
+
+ if (waitVRT) {
+ _vsync_in();
+ }
+}
+
+/* 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->OriginOffset = af_width*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, 0, 0, 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;
+}
+
+AF_PALETTE af_pal[256];
+
+/* SetPaletteData:
+ * Palette setting routine.
+ */
+void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT)
+{
+ int i;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ outportb(0x3c8,index);
+ for (i=index; i=mouse_fg&&index+num=0)) {
+ alter_vga_register(0x3c4,0x12,3,2);//index 12 - enable access to extended DAC palette entries
+ outportb(0x3c8,0xf);//cursor foreground
+ outportb(0x3c9,af_pal[mouse_fg].red);
+ outportb(0x3c9,af_pal[mouse_fg].green);
+ outportb(0x3c9,af_pal[mouse_fg].blue);
+ outportb(0x3c8,0);//cursor background
+ outportb(0x3c9,af_pal[0].red);
+ outportb(0x3c9,af_pal[0].green);
+ outportb(0x3c9,af_pal[0].blue);
+ alter_vga_register(0x3c4,0x12,3,0);//index 12 - enable access to extended DAC palette entries
+ }
+}
+
+/* SetBank32:
+ * Relocatable bank switch function. This is called with a bank number in
+ * %edx. I'm not sure what registers it is allowed to clobber, so it is
+ * probably a good idea to save them all.
+ *
+ * This function may be copied anywhere within the address space of the
+ * calling program, so it must be 100% relocatable. That means that you
+ * must not refer to any internal variables of the /AF driver, because
+ * you know nothing about where in memory it will be located. Your only
+ * input is the bank number in %edx, and your only output should be
+ * changing the relevant hardware registers.
+ *
+ * If you are unable to provide a relocatable bank switcher of this type,
+ * remove this function (clear the SetBank32 pointer to NULL during the
+ * header init), and fill in the SetBank() routine below instead. Allegro
+ * only ever uses SetBank(), so there will be no problem with leaving this
+ * function out, but you may have problems running other VBE/AF
+ * applications if you don't provide it.
+ *
+ */
+asm ("
+
+ .globl _SetBank32, _SetBank32End
+
+ .align 4
+ _SetBank32:
+ pushl %edx /* I have 16K bank gran, but driver probably */
+ movb %dl,%ah /* don't know about that, so I must multiply by 4 */
+ shlb $2,%ah
+ movl $0x3CE, %edx
+ movb $9, %al
+ outw %ax, %dx
+ popl %edx
+ ret
+ _SetBank32End:
+
+");
+
+/* SetBank:
+ * C-callable bank switch function. This version simply chains to the
+ * relocatable SetBank32() above. If you can't provide a relocatable
+ * function (because you need access to global variables or some part
+ * of the /AF driver structure), you should put the bank switch code
+ * here instead.
+ */
+void SetBank(AF_DRIVER *af, long bank)
+{
+ asm("
+ movb %%al,%%ah
+ shlb $2,%%ah
+ movl $0x3CE, %%edx
+ movb $9, %%al
+ outw %%ax, %%dx"
+ ::"a" (bank):"%dx");
+ af_bank = bank;
+}
+
+#ifdef NO_CACHE
+#define SET_ROP_MODE(bltrop,bltmode) { CIR_BLTROP(bltrop); \
+ CIR_BLTMODE(bltmode);}
+
+#define SET_ROP_MODEMMIO(bltrop,bltmode) CIR_ROP_MODEMMIO(bltrop,bltmode);
+
+#define SET_TRANS(color) CIR_TRANS(color)
+
+#define SET_TRANSMMIO(color) CIR_TRANSMMIO(color)
+
+#define SET_WIDTH_HEIGHT(width,height) {CIR_WIDTH(width); \
+ CIR_HEIGHT(height);}
+
+#define SET_FG8(fg) CIR_FORG8(fg)
+#define SET_FG16(fg) CIR_FORG16(fg)
+#define SET_FG24(fg) CIR_FORG24(fg)
+#define SET_FG32(fg) CIR_FORG32(fg)
+
+#define SET_BG8(bg) CIR_BACKG8(bg)
+#define SET_BG16(bg) CIR_BACKG16(bg)
+#define SET_BG24(bg) CIR_BACKG24(bg)
+#define SET_BG32(bg) CIR_BACKG32(bg)
+
+#define SET_FG8MMIO(fg) CIR_FORG8MMIO(fg)
+#define SET_FG16MMIO(fg) CIR_FORG16MMIO(fg)
+#define SET_FG24MMIO(fg) CIR_FORG24MMIO(fg)
+#define SET_FG32MMIO(fg) CIR_FORG32MMIO(fg)
+
+#define SET_BG8MMIO(bg) CIR_BACKG8MMIO(bg)
+#define SET_BG16MMIO(bg) CIR_BACKG16MMIO(bg)
+#define SET_BG24MMIO(bg) CIR_BACKG24MMIO(bg)
+#define SET_BG32MMIO(bg) CIR_BACKG32MMIO(bg)
+
+#else
+
+#define SET_ROP_MODE(bltrop,bltmode) \
+ if (cir_oldbltrop!=bltrop) { \
+ cir_oldbltrop=bltrop; \
+ CIR_BLTROP(cir_oldbltrop); \
+ } \
+ if (cir_oldbltmode!=bltmode) { \
+ cir_oldbltmode=bltmode; \
+ CIR_BLTMODE(cir_oldbltmode); \
+ }
+
+#define SET_ROP_MODEMMIO(bltrop,bltmode) \
+ if (cir_oldbltrop!=bltrop) { \
+ if (cir_oldbltmode!=bltmode) { \
+ cir_oldbltmode=bltmode; \
+ cir_oldbltrop=bltrop; \
+ CIR_ROP_MODEMMIO(bltrop,bltmode); \
+ } else { \
+ cir_oldbltrop=bltrop; \
+ CIR_BLTROPMMIO(bltrop); \
+ } \
+ } else if (cir_oldbltmode!=bltmode) { \
+ cir_oldbltmode=bltmode; \
+ CIR_BLTMODEMMIO(bltmode); \
+ }
+
+
+#define SET_FG8(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG8(cir_fg); \
+ }
+
+#define SET_FG16(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG16(cir_fg); \
+ }
+
+#define SET_FG24(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG24(cir_fg); \
+ }
+
+#define SET_FG32(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG32(cir_fg); \
+ }
+
+#define SET_BG8(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG8(cir_bg); \
+ }
+
+#define SET_BG16(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG16(cir_bg); \
+ }
+
+#define SET_BG24(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG24(cir_bg); \
+ }
+
+#define SET_BG32(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG32(cir_bg); \
+ }
+
+#define SET_FG8MMIO(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG8(cir_fg); \
+ }
+
+#define SET_FG16MMIO(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG16(cir_fg); \
+ }
+
+#define SET_FG24MMIO(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG24(cir_fg); \
+ }
+
+#define SET_FG32MMIO(color) if (cir_fg!=color) { \
+ cir_fg=color; \
+ CIR_FORG32(cir_fg); \
+ }
+
+#define SET_BG8MMIO(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG8(cir_bg); \
+ }
+
+#define SET_BG16MMIO(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG16(cir_bg); \
+ }
+
+#define SET_BG24MMIO(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG24(cir_bg); \
+ }
+
+#define SET_BG32MMIO(color) if (cir_bg!=color) { \
+ cir_bg=color; \
+ CIR_BACKG32(cir_bg); \
+ }
+
+#define SET_TRANS(color) if (cir_trans!=(color)) { \
+ cir_trans=color; \
+ CIR_TRANS(cir_trans); \
+ }
+
+#define SET_TRANSMMIO(color) if (cir_trans!=(color)) { \
+ cir_trans=color; \
+ CIR_TRANSMMIO(cir_trans); \
+ }
+
+#define SET_WIDTH_HEIGHT(width,height) {CIR_HEIGHT(height); \
+ CIR_WIDTH(width);}
+
+/*
+//doesn't work on 7543 but should on 5426-9
+#define SET_HEIGHT(height) if (cir_height!=height){ \
+ cir_height=height; \
+ CIR_HEIGHT(height); \
+ }
+*/
+
+#endif
+
+inline void waitidle()
+{
+ if (need_wait) {
+ outportb(GRX,0x31);
+ while (inportb(GRX+1)&1);
+ need_wait=0;
+ }
+}
+
+inline void waitidleMMIO()
+{
+ if (need_wait) {
+ while (inmb(0x40)&1);
+ need_wait=0;
+ }
+}
+
+/* WaitTillIdle:
+ * Delay until the hardware controller has finished drawing.
+ */
+
+#define WaitMacro(bpp) \
+void WaitTillIdle##bpp##(AF_DRIVER *af) \
+{ \
+ if (need_wait) { \
+ outportb(GRX,0x31); \
+ while (inportb(GRX+1)&1); \
+ need_wait=0; \
+ } \
+ SET_FG##bpp##(0); \
+}
+
+WaitMacro(8)
+WaitMacro(16)
+WaitMacro(24)
+WaitMacro(32)
+
+#define WaitMacroMMIO(bpp) \
+void WaitTillIdle##bpp##MMIO(AF_DRIVER *af) \
+{ \
+ if (need_wait) { \
+ while (inmb(0x40)&1); \
+ need_wait=0; \
+ } \
+ SET_FG##bpp##MMIO(0); \
+}
+
+WaitMacroMMIO(8)
+WaitMacroMMIO(16)
+WaitMacroMMIO(24)
+WaitMacroMMIO(32)
+
+
+int af_mix_fore(int mix)
+{
+ switch (mix) {
+ case AF_REPLACE_MIX:
+ return CIR_ROP_COPY;
+ case AF_AND_MIX:
+ return CIR_ROP_AND;
+ case AF_XOR_MIX:
+ return CIR_ROP_XOR;
+ case AF_OR_MIX:
+ return CIR_ROP_OR;
+ case AF_NOP_MIX:
+ return CIR_ROP_NOP;
+ default:
+ return CIR_ROP_NOP;
+ }
+}
+
+/* SetMix:
+ * Specifies the pixel mix mode to be used for hardware drawing functions
+ * (not the blit routines: they take an explicit mix parameter). Both
+ * parameters should both be one of the AF_mixModes enum defined in vbeaf.h.
+ *
+ * VBE/AF requires all drivers to support the REPLACE, AND, OR, XOR,
+ * and NOP mix types. This file implements all the required types, but
+ * Allegro only actually uses the REPLACE and XOR modes for scanline and
+ * rectangle fills, REPLACE mode for blitting and color pattern drawing,
+ * and either REPLACE or foreground REPLACE and background NOP for mono
+ * pattern drawing.
+ *
+ * If you want, you can set the afHaveROP2 bit in the mode attributes
+ * field and then implement all the AF_R2_* modes as well, but that isn't
+ * required by the spec, and Allegro never uses them.
+ */
+void SetMix(AF_DRIVER *af, long foreMix, long backMix)
+{
+ af_fore_mix = foreMix;
+ cir_bltrop=af_mix_fore(foreMix);
+ if (backMix == AF_FORE_MIX)
+ af_back_mix = foreMix;
+ else
+ af_back_mix = backMix;
+ if (backMix == AF_NOP_MIX) //transparent
+ cir_bltmode=CIR_BLT_TRANS|CIR_BLT_PATT|CIR_BLT_COLEXP|cir_pixmode;
+ else
+ cir_bltmode=CIR_BLT_PATT|CIR_BLT_COLEXP|cir_pixmode;
+}
+
+
+inline unsigned char rolb(unsigned char x, unsigned char count)
+{
+ asm volatile ("rolb %%cl,%b2":"=a" (x):"c" (count),"r" (x));
+ return x;
+}
+
+unsigned char mono_pattern[16];
+/* stored color pattern data */
+unsigned long color_pattern[8][64];
+unsigned long *current_color_pattern = color_pattern[0];
+
+int last_mono_x,last_mono_y;
+int last_color_x,last_color_y;
+
+
+#define copymonomacro(mmio,bpp) \
+void copymonopattern##bpp####mmio##(AF_DRIVER *af,int x,int y)\
+{ \
+ int i; \
+ unsigned char *p; \
+ \
+ SET_FG##bpp####mmio##(0); \
+ if ((last_mono_y!=(y&7))||(last_mono_x!=(x&7))) { \
+ last_mono_y=y&7; \
+ last_mono_x=x&7; \
+ if (af_linear) { \
+ p=af->LinearMem+af_memory-MONOPATTSTART; \
+ for (i=0;i<8;i++) \
+ p[i]=rolb(mono_pattern[i+last_mono_y],last_mono_x); \
+ } else { \
+ p=af->BankedMem+DISPLACEMENT-MONOPATTSTART; \
+ SetBank(af,af_last_bank); \
+ for (i=0;i<8;i++) \
+ p[i]=rolb(mono_pattern[i+last_mono_y],last_mono_x); \
+ cir_bltmode|=CIR_BLT_COLEXP; \
+ } \
+ } \
+}
+
+copymonomacro(,8)
+copymonomacro(,16)
+copymonomacro(,24)
+copymonomacro(,32)
+
+copymonomacro(MMIO,8)
+copymonomacro(MMIO,16)
+copymonomacro(MMIO,24)
+copymonomacro(MMIO,32)
+
+#define copycolormacro(mmio,bpp) \
+void copycolorpattern##bpp####mmio##(AF_DRIVER *af,int x,int y) \
+{ \
+ int i,j; \
+ \
+ SET_FG##bpp####mmio##(0); \
+ if ((last_color_y!=(y&7))||(last_color_x!=(x&7))) { \
+ last_color_y=y&7; \
+ last_color_x=x&7; \
+ switch (bpp) { \
+ case 8: \
+ if (af_linear) { \
+ unsigned char *p=af->LinearMem+af_memory-COLPATTSTART; \
+ \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } else { \
+ unsigned char *p=af->BankedMem+DISPLACEMENT-COLPATTSTART; \
+ \
+ SetBank(af,af_last_bank); \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } \
+ case 15: \
+ case 16: \
+ if (af_linear) { \
+ unsigned short *p=af->LinearMem+af_memory-COLPATTSTART; \
+ \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } else { \
+ unsigned short *p=af->BankedMem+DISPLACEMENT-COLPATTSTART; \
+ \
+ SetBank(af,af_last_bank); \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } \
+ case 24: \
+ if (af_linear) { \
+ unsigned char *p=af->LinearMem+af_memory-COLPATTSTART; \
+ \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ *((unsigned long *)(((unsigned char *)p)+(i*8+j)*3))=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } else { \
+ unsigned char *p=af->BankedMem+DISPLACEMENT-COLPATTSTART; \
+ \
+ SetBank(af,af_last_bank); \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ *((unsigned long *)(((unsigned char *)p)+(i*8+j)*3))=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } \
+ case 32: \
+ if (af_linear) { \
+ unsigned long *p=af->LinearMem+af_memory-COLPATTSTART; \
+ \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } else { \
+ unsigned long *p=af->BankedMem+DISPLACEMENT-COLPATTSTART; \
+ \
+ SetBank(af,af_last_bank); \
+ for (i=0;i<8;i++) \
+ for (j=0;j<8;j++) \
+ p[i*8+j]=current_color_pattern[((i+last_color_y)&7)*8+((j+last_color_x)&7)];\
+ break; \
+ } \
+ } \
+ cir_bltmode&=~CIR_BLT_COLEXP; \
+ } \
+}
+
+copycolormacro(,8)
+copycolormacro(,16)
+copycolormacro(,24)
+copycolormacro(,32)
+
+copycolormacro(MMIO,8)
+copycolormacro(MMIO,16)
+copycolormacro(MMIO,24)
+copycolormacro(MMIO,32)
+
+/* 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)
+{
+ int i;
+
+ last_mono_x=last_mono_y=-1;
+ for (i=0;i<16;i++)
+ mono_pattern[i]=pattern[i&7];
+}
+
+/* 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).
+ *
+ * VBE/AF supports 8 different color patterns, which may be downloaded
+ * individually and then selected for use with the Use8x8ColorPattern()
+ * function. If the card is not able to cache these patterns in hardware,
+ * the driver is responsible for storing them internally and downloading
+ * the appropriate data when Use8x8ColorPattern() is called.
+ *
+ * Allegro only actually ever uses the first of these patterns, so
+ * you only need to bother about this if you want your code to work
+ * with other programs as well.
+ */
+void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
+{
+ int i;
+
+ for (i=0; i<64; i++)
+ color_pattern[index][i] = pattern[i];
+}
+
+
+
+/* Use8x8ColorPattern:
+ * Selects one of the patterns previously downloaded by Set8x8ColorPattern().
+ */
+void Use8x8ColorPattern(AF_DRIVER *af, int index)
+{
+ last_color_x=last_color_y=-1;
+ current_color_pattern=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.
+ */
+#define DrawScanMacro(mmio,bpp)\
+void DrawScan##bpp####mmio##(AF_DRIVER *af, long color, long y, long x1, long x2)\
+{ \
+ if (x2 < x1) { \
+ int tmp = x1; \
+ x1 = x2; \
+ x2 = tmp; \
+ } \
+ \
+ y += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ need_wait=1; \
+ SET_ROP_MODE(cir_bltrop,cir_bltmode); \
+ SET_FG##bpp####mmio##(color); \
+ SET_WIDTH_HEIGHT##mmio##((x2-x1)*(bpp/8)-1,0);\
+ SET_DSTADDR##mmio##(y*af_width+x1*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offscreen); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawScanMacro(,8)
+DrawScanMacro(,16)
+DrawScanMacro(,24)
+DrawScanMacro(,32)
+
+DrawScanMacro(MMIO,8)
+DrawScanMacro(MMIO,16)
+DrawScanMacro(MMIO,24)
+DrawScanMacro(MMIO,32)
+
+/* 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.
+ */
+#define DrawPattScanMacro(mmio,bpp)\
+void DrawPattScan##bpp####mmio##(AF_DRIVER *af, long foreColor, long backColor, long y, long x1, long x2)\
+{ \
+ if (x2 < x1) { \
+ int tmp = x1; \
+ x1 = x2; \
+ x2 = tmp; \
+ } \
+ \
+ y += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ copymonopattern##bpp####mmio##(af,x1,y); \
+ need_wait=1; \
+ SET_ROP_MODE(cir_bltrop,cir_bltmode); \
+ SET_FG##bpp####mmio##(foreColor); \
+ SET_BG##bpp####mmio##(backColor); \
+ SET_WIDTH_HEIGHT##mmio##((x2-x1)*(bpp/8)-1,0);\
+ SET_DSTADDR##mmio##(y*af_width+x1*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offmono); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawPattScanMacro(,8)
+DrawPattScanMacro(,16)
+DrawPattScanMacro(,24)
+DrawPattScanMacro(,32)
+
+DrawPattScanMacro(MMIO,8)
+DrawPattScanMacro(MMIO,16)
+DrawPattScanMacro(MMIO,24)
+DrawPattScanMacro(MMIO,32)
+
+/* DrawColorPattScan:
+ * Fills a scanline using the current color pattern and mix mode.
+ */
+#define DrawColorPattScanMacro(mmio,bpp)\
+void DrawColorPattScan##bpp####mmio##(AF_DRIVER *af, long y, long x1, long x2)\
+{ \
+ if (x2 < x1) { \
+ int tmp = x1; \
+ x1 = x2; \
+ x2 = tmp; \
+ } \
+ \
+ y += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ copycolorpattern##bpp####mmio##(af,x1,y); \
+ need_wait=1; \
+ SET_ROP_MODE##mmio##(cir_bltrop,cir_bltmode);\
+ SET_WIDTH_HEIGHT##mmio##((x2-x1)*(bpp/8)-1,0);\
+ SET_DSTADDR##mmio##(y*af_width+x1*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offcolor); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawColorPattScanMacro(,8)
+DrawColorPattScanMacro(,16)
+DrawColorPattScanMacro(,24)
+DrawColorPattScanMacro(,32)
+
+DrawColorPattScanMacro(MMIO,8)
+DrawColorPattScanMacro(MMIO,16)
+DrawColorPattScanMacro(MMIO,24)
+DrawColorPattScanMacro(MMIO,32)
+
+/* DrawRect:
+ * Fills a rectangle in the current foreground mix mode.
+ */
+#define DrawRectMacro(mmio,bpp)\
+void DrawRect##bpp####mmio##(AF_DRIVER *af, unsigned long color, long left, long top, long width, long height)\
+{ \
+ top += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ need_wait=1; \
+ SET_ROP_MODE##mmio##(cir_bltrop,cir_bltmode);\
+ SET_FG##bpp####mmio##((int)color); \
+ SET_WIDTH_HEIGHT##mmio##(width*(bpp/8)-1,height-1);\
+ SET_DSTADDR##mmio##(top*af_width+left*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offscreen); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawRectMacro(,8)
+DrawRectMacro(,16)
+DrawRectMacro(,24)
+DrawRectMacro(,32)
+
+DrawRectMacro(MMIO,8)
+DrawRectMacro(MMIO,16)
+DrawRectMacro(MMIO,24)
+DrawRectMacro(MMIO,32)
+
+/* 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.
+ */
+#define DrawPattRectMacro(mmio,bpp)\
+void DrawPattRect##bpp####mmio##(AF_DRIVER *af, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height)\
+{ \
+ top += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ copymonopattern##bpp####mmio##(af,left,top);\
+ need_wait=1; \
+ SET_ROP_MODE##mmio##(cir_bltrop,cir_bltmode);\
+ SET_FG##bpp####mmio##((int)foreColor); \
+ SET_BG##bpp####mmio##((int)backColor); \
+ SET_WIDTH_HEIGHT##mmio##(width*(bpp/8)-1,height-1);\
+ SET_DSTADDR##mmio##(top*af_width+left*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offmono); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawPattRectMacro(,8)
+DrawPattRectMacro(,16)
+DrawPattRectMacro(,24)
+DrawPattRectMacro(,32)
+
+DrawPattRectMacro(MMIO,8)
+DrawPattRectMacro(MMIO,16)
+DrawPattRectMacro(MMIO,24)
+DrawPattRectMacro(MMIO,32)
+
+/* DrawColorPattRect:
+ * Fills a rectangle using the current color pattern and mix mode.
+ */
+#define DrawColorPattRectMacro(mmio,bpp)\
+void DrawColorPattRect##bpp####mmio##(AF_DRIVER *af, long left, long top, long width, long height)\
+{ \
+ top += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ copycolorpattern##bpp####mmio##(af,left,top);\
+ need_wait=1; \
+ SET_ROP_MODE##mmio##(cir_bltrop,cir_bltmode);\
+ SET_WIDTH_HEIGHT##mmio##(width*(bpp/8)-1,height-1);\
+ SET_DSTADDR##mmio##(top*af_width+left*(bpp/8));\
+ SET_SRCADDR##mmio##(cir_offcolor); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+DrawColorPattRectMacro(,8)
+DrawColorPattRectMacro(,16)
+DrawColorPattRectMacro(,24)
+DrawColorPattRectMacro(,32)
+
+DrawColorPattRectMacro(MMIO,8)
+DrawColorPattRectMacro(MMIO,16)
+DrawColorPattRectMacro(MMIO,24)
+DrawColorPattRectMacro(MMIO,32)
+
+/* 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.
+ */
+#define BitBltMacro(mmio,bpp,pixmode)\
+void BitBlt##bpp####mmio##(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op)\
+{ \
+ unsigned long pdst,psrc; \
+ int bltmode=pixmode,bltrop; \
+ \
+ top += af_active_page*af_height; \
+ dstTop += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ width*=(bpp/8);width--;height--; \
+ left*=(bpp/8);dstLeft*=(bpp/8); \
+ need_wait=1; \
+ if ((dstTop>top)||((top==dstTop)&&(dstLeft>left))) {\
+ psrc = (((top + height) * af_width) + left + width);\
+ pdst = (((dstTop + height) * af_width) + dstLeft + width);\
+ bltmode|=CIR_BLT_BACK; \
+ } else { \
+ psrc = ((top * af_width) + left); \
+ pdst = ((dstTop * af_width) + dstLeft); \
+ } \
+ SET_WIDTH_HEIGHT##mmio##(width,height); \
+ SET_SRCADDR##mmio##(psrc); \
+ SET_DSTADDR##mmio##(pdst); \
+ bltrop=af_mix_fore(op); \
+ SET_ROP_MODE##mmio##(bltrop,bltmode); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+BitBltMacro(,8,CIR_BLT_PIX8)
+BitBltMacro(,16,CIR_BLT_PIX16)
+BitBltMacro(,24,CIR_BLT_PIX24)
+BitBltMacro(,32,CIR_BLT_PIX32)
+
+BitBltMacro(MMIO,8,CIR_BLT_PIX8)
+BitBltMacro(MMIO,16,CIR_BLT_PIX16)
+BitBltMacro(MMIO,24,CIR_BLT_PIX24)
+BitBltMacro(MMIO,32,CIR_BLT_PIX32)
+
+/* 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.
+ */
+#define SrcTransBltMacro(mmio,bpp,pixmode)\
+void SrcTransBlt##bpp####mmio##(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent)\
+{ \
+ unsigned long pdst,psrc; \
+ int bltmode=pixmode|CIR_BLT_TRANS,bltrop; \
+ \
+ top += af_active_page*af_height; \
+ dstTop += af_active_page*af_height; \
+ waitidle##mmio##(); \
+ width*=(bpp/8);width--;height--; \
+ left*=(bpp/8);dstLeft*=(bpp/8); \
+ need_wait=1; \
+ if ((dstTop>top)||((top==dstTop)&&(dstLeft>left))) {\
+ psrc = (((top + height) * af_width) + left + width);\
+ pdst = (((dstTop + height) * af_width) + dstLeft + width);\
+ bltmode|=CIR_BLT_BACK; \
+ } else { \
+ psrc = ((top * af_width) + left); \
+ pdst = ((dstTop * af_width) + dstLeft); \
+ } \
+ SET_TRANS##mmio##((int)transparent); \
+ SET_WIDTH_HEIGHT##mmio##(width,height); \
+ SET_SRCADDR##mmio##(psrc); \
+ SET_DSTADDR##mmio##(pdst); \
+ bltrop=af_mix_fore(op); \
+ SET_ROP_MODE##mmio##(bltrop,bltmode); \
+ CIR_CMD(CIR_CMD_RUN); \
+}
+
+SrcTransBltMacro(,8,CIR_BLT_PIX8)
+SrcTransBltMacro(,16,CIR_BLT_PIX16)
+SrcTransBltMacro(,24,CIR_BLT_PIX24)
+SrcTransBltMacro(,32,CIR_BLT_PIX32)
+
+SrcTransBltMacro(MMIO,8,CIR_BLT_PIX8)
+SrcTransBltMacro(MMIO,16,CIR_BLT_PIX16)
+SrcTransBltMacro(MMIO,24,CIR_BLT_PIX24)
+SrcTransBltMacro(MMIO,32,CIR_BLT_PIX32)
+
+int hw_cur_x=0,hw_cur_y=0;
+
+void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor)
+{
+ int i,j;
+ unsigned long *p,andMask,xorMask;
+
+ af->WaitTillIdle(af);
+ alter_vga_register(0x3c4,0x12,3,0);
+ write_vga_register(0x3d4,11,0x24);
+ if (af_linear)
+ p=af->LinearMem+af_memory-CURSORSTART;
+ else {
+ p=af->BankedMem+DISPLACEMENT-CURSORSTART;
+ SetBank(af,af_last_bank);
+ }
+ for (i=0;i<32;i++) {
+ andMask=xorMask=0;
+ for (j=0;j<32;j++) {
+ if (cursor->andMask[i]&(1<xorMask[i]&(1<xorMask[i]&(1<hotx;
+ hw_cur_y=cursor->hoty;
+ write_vga_register(0x3c4,0x13,0x38);
+ if (cir_cursor_visible)
+ alter_vga_register(0x3c4,0x12,1,1);
+}
+
+void SetCursorPos(AF_DRIVER *af, long x, long y)
+{
+ x-=hw_cur_x;
+ if (x<0) x=0;
+ y-=hw_cur_y;
+ if (y<0) y=0;
+ __asm__ (
+ "movw $0x3c4,%%dx
+ outw %%ax,%%dx
+ movw %%bx,%%ax
+ outw %%ax,%%dx"
+ :
+ :"a" ((x<<5)+0x10),"b" ((y<<5)+0x11)
+ :"%dx");
+}
+
+void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green, unsigned char blue)
+{
+ alter_vga_register(0x3c4,0x12,2,2);//index 12 - enable access to extended DAC palette entries
+ if (af_bpp==8) {
+ mouse_fg=red;
+ outportb(0x3c8,0xf);//cursor foreground
+ outportb(0x3c9,af_pal[mouse_fg].red);
+ outportb(0x3c9,af_pal[mouse_fg].green);
+ outportb(0x3c9,af_pal[mouse_fg].blue);
+ outportb(0x3c8,0);//cursor background
+ outportb(0x3c9,af_pal[0].red);
+ outportb(0x3c9,af_pal[0].green);
+ outportb(0x3c9,af_pal[0].blue);
+ } else {
+ outportb(0x3c8,0xf);//cursor foreground
+ outportb(0x3c9,red);
+ outportb(0x3c9,green);
+ outportb(0x3c9,blue);
+ outportb(0x3c8,0);//cursor background
+ outportb(0x3c9,0);
+ outportb(0x3c9,0);
+ outportb(0x3c9,0);
+ }
+ alter_vga_register(0x3c4,0x12,2,0);//index 12 - disable access to extended DAC palette entries
+}
+
+void ShowCursor(AF_DRIVER *af, long visible)
+{
+ if (visible) {
+ alter_vga_register(0x3c4,0x12,5,1);
+ cir_cursor_visible=1;
+ } else {
+ alter_vga_register(0x3c4,0x12,5,0);
+ cir_cursor_visible=0;
+ }
+}
+
+#define BitBltSysMacro(mmio,bpp,pixmode) \
+void BitBltSys##bpp####mmio##(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op)\
+{ \
+ unsigned long pdst; \
+ int bltmode=pixmode,bltrop; \
+ \
+ width*=(bpp/8);width--;height--; \
+ srcLeft*=(bpp/8);dstLeft*=(bpp/8); \
+ waitidle##mmio##(); \
+ need_wait=1; \
+ dstTop += af_active_page*af_height; \
+ pdst = dstTop * af_width + dstLeft; \
+ SET_WIDTH_HEIGHT##mmio##(width,height); \
+ SET_SRCADDR##mmio##(0); \
+ SET_DSTADDR##mmio##(pdst); \
+ bltrop=af_mix_fore(op); \
+ bltmode|=CIR_BLT_MEM; \
+ SET_ROP_MODE##mmio##(bltrop,bltmode); \
+ CIR_CMD(CIR_CMD_RUN); \
+ width++;height++; \
+ __asm__ __volatile__ ("\
+ cld;\
+ 1:;\
+ pushl %%edi;\
+ pushl %%ecx;\
+ rep; movsl;\
+ movsw;\
+ movsw;\
+ popl %%ecx;\
+ addl %%ebx,%%esi;\
+ popl %%edi;\
+ decl %%edx;\
+ jnz 1b\
+ "\
+ ::"S" (srcAddr+srcTop*srcPitch+srcLeft), "D" (af_linear?af->LinearMem:af->BankedMem), "b" (srcPitch-((width-1)&0xfffffffc)-4), "c" ((width-1)>>2), "d" (height)\
+ :"eax","ebx","ecx","edx","esi","edi","cc"\
+ );\
+}
+
+BitBltSysMacro(,8,CIR_BLT_PIX8)
+BitBltSysMacro(,16,CIR_BLT_PIX16)
+BitBltSysMacro(,24,CIR_BLT_PIX24)
+BitBltSysMacro(,32,CIR_BLT_PIX32)
+
+BitBltSysMacro(MMIO,8,CIR_BLT_PIX8)
+BitBltSysMacro(MMIO,16,CIR_BLT_PIX16)
+BitBltSysMacro(MMIO,24,CIR_BLT_PIX24)
+BitBltSysMacro(MMIO,32,CIR_BLT_PIX32)
+
+#define SrcTransBltSysMacro(mmio,bpp,pixmode)\
+void SrcTransBltSys##bpp####mmio##(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent)\
+{ \
+ unsigned long pdst; \
+ int bltmode,bltrop; \
+ \
+ width*=(bpp/8);width--;height--; \
+ srcLeft*=(bpp/8);dstLeft*=(bpp/8); \
+ waitidle##mmio##(); \
+ need_wait=1; \
+ dstTop += af_active_page*af_height; \
+ pdst = dstTop * af_width + dstLeft; \
+ bltrop=af_mix_fore(op); \
+ bltmode=CIR_BLT_MEM|CIR_BLT_TRANS|pixmode;\
+ SET_ROP_MODE##mmio##(bltrop,bltmode); \
+ SET_WIDTH_HEIGHT##mmio##(width,height); \
+ SET_TRANS##mmio##((int)transparent); \
+ SET_SRCADDR##mmio##(0); \
+ SET_DSTADDR##mmio##(pdst); \
+ CIR_CMD(CIR_CMD_RUN); \
+ width++;height++; \
+ __asm__ __volatile__ (" \
+ cld; \
+ 1:; \
+ pushl %%edi; \
+ pushl %%ecx; \
+ rep; movsl; \
+ movsw; \
+ movsw; \
+ popl %%ecx; \
+ addl %%ebx,%%esi; \
+ popl %%edi; \
+ decl %%edx; \
+ jnz 1b; \
+ " \
+ : \
+ :"S" (srcAddr+srcTop*srcPitch+srcLeft), "D" (af_linear?af->LinearMem:af->BankedMem), "b" (srcPitch-((width-1)&0xfffffffc)-4), "c" ((width-1)>>2), "d" (height)\
+ :"eax","ebx","ecx","edx","esi","edi","cc"\
+ ); \
+}
+
+SrcTransBltSysMacro(,8,CIR_BLT_PIX8)
+SrcTransBltSysMacro(,16,CIR_BLT_PIX16)
+SrcTransBltSysMacro(,24,CIR_BLT_PIX24)
+SrcTransBltSysMacro(,32,CIR_BLT_PIX32)
+
+SrcTransBltSysMacro(MMIO,8,CIR_BLT_PIX8)
+SrcTransBltSysMacro(MMIO,16,CIR_BLT_PIX16)
+SrcTransBltSysMacro(MMIO,24,CIR_BLT_PIX24)
+SrcTransBltSysMacro(MMIO,32,CIR_BLT_PIX32)
+
+inline void shiftleft(unsigned char *line,int bytes,unsigned char bits)
+{
+ asm("
+ movb $8,%%ch
+ addb %%cl,%%ch
+ movb %%dl,%%al
+1:
+ movb (%%esi),%%ah
+ andl $0xffff,%%eax
+ shll %%cl,%%eax
+ movb %%ah,(%%esi)
+ xchgb %%ch,%%cl
+ shrl %%cl,%%eax
+ decl %%esi
+ xchgb %%ch,%%cl
+ decl %%ebx
+ jnz 1b"
+ ::"S" (line+bytes-1), "c" ((bits&31)|((32-(bits&31))<<8)), "d" (0), "b" (bytes));
+}
+
+unsigned char lines[1024];
+
+#define PutMonoImageMacro(mmio,bpp,pixmode)\
+void PutMonoImage##bpp####mmio##(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 pdst; \
+ int i,j,bytelen=(width+7)/8; \
+ int bltmode=CIR_BLT_MEM|CIR_BLT_COLEXP|pixmode;\
+ \
+ \
+ if (width*8==byteWidth) { \
+ for (i=0;iLinearMem:af->BankedMem), "c" ((height*bytelen+3)/4), "d" (height)\
+ :"eax","ecx","edx","esi","edi","cc" \
+ ); \
+}
+
+PutMonoImageMacro(,8,CIR_BLT_PIX8)
+PutMonoImageMacro(,16,CIR_BLT_PIX16)
+PutMonoImageMacro(,24,CIR_BLT_PIX24)
+PutMonoImageMacro(,32,CIR_BLT_PIX32)
+
+PutMonoImageMacro(MMIO,8,CIR_BLT_PIX8)
+PutMonoImageMacro(MMIO,16,CIR_BLT_PIX16)
+PutMonoImageMacro(MMIO,24,CIR_BLT_PIX24)
+PutMonoImageMacro(MMIO,32,CIR_BLT_PIX32)
+
+/* 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.
+ */
+
+#define SetupMacro(mmio,bpp)\
+void SetupFuncPtr##bpp####mmio##(AF_DRIVER *af)\
+{\
+ af->DrawScan = DrawScan##bpp####mmio##;\
+ af->DrawPattScan = DrawPattScan##bpp####mmio##;\
+ af->DrawColorPattScan = DrawColorPattScan##bpp####mmio##;\
+ af->DrawRect = DrawRect##bpp####mmio##;\
+ af->DrawPattRect = DrawPattRect##bpp####mmio##;\
+ af->DrawColorPattRect = DrawColorPattRect##bpp####mmio##;\
+ af->BitBlt = BitBlt##bpp####mmio##;\
+ af->BitBltSys = BitBltSys##bpp####mmio##;\
+ af->SrcTransBlt = SrcTransBlt##bpp####mmio##;\
+ af->SrcTransBltSys = SrcTransBltSys##bpp####mmio##;\
+ af->WaitTillIdle = WaitTillIdle##bpp####mmio##;\
+ af->PutMonoImage = PutMonoImage##bpp####mmio##;\
+}
+
+
+SetupMacro(,8);
+SetupMacro(,16);
+SetupMacro(,24);
+SetupMacro(,32);
+
+SetupMacro(MMIO,8);
+SetupMacro(MMIO,16);
+SetupMacro(MMIO,24);
+SetupMacro(MMIO,32);
+
+int SetupDriver(AF_DRIVER *af)
+{
+ RM_REGS regs;
+ int i,j,card,bus_type=0;
+
+ regs.x.ax=0x1200; //cirrus extended bios
+ regs.x.bx=0x80; //get chip version
+ rm_int(0x10,®s);
+ card=regs.h.al;
+ for (i=0;iTotalMemory=(af_memory-RESERVED_VRAM)/1024;
+ if (!detect_info[cir_card].pcinum)
+ goto pcinotfound;
+ regs.x.ax = 0xB101;
+ rm_int(0x1A, ®s);
+ if (regs.h.ah)
+ goto pcinotfound;
+ regs.x.ax = 0xB102;
+ regs.x.cx = detect_info[cir_card].pcinum;
+ regs.x.dx = CIRRUS_PCI_VENDOR_ID;
+ regs.x.si = 0;
+ rm_int(0x1A, ®s);
+ if (regs.h.ah)
+ goto pcinotfound;
+ bus_type=regs.x.bx;
+ af->PCIVendorID=CIRRUS_PCI_VENDOR_ID;
+ af->PCIDeviceID=detect_info[cir_card].pcinum;
+ regs.x.bx = bus_type;
+ regs.x.ax = 0xB10A;
+ regs.x.di = 16;
+ rm_int(0x1A, ®s);
+ linear_addr = regs.d.ecx & 0xff000000;
+pcinotfound:
+
+ i=j=0;
+ while (mode_list[i].w!=0) {
+ regs.h.ah=0x12;/*cirrus bios extensions*/
+ regs.h.al=mode_list[i].num;
+ regs.d.ebx=0xA0;/*get availability of video mode*/
+ rm_int(0x10,®s);
+ if ((regs.h.ah&1)&&(mode_list[i].bpp<24||(mode_list[i].bpp==24
+ &&cir_useblt24)||(mode_list[i].bpp==32&&cir_useblt32))) {
+ available_modes[j++]=i+1;
+ }
+ i++;
+ }
+ num_modes=i;
+ available_modes[j]=-1;
+
+ /* pointer to a list of the available mode numbers, ended by -1.
+ * Our mode numbers just count up from 1, so the mode numbers can
+ * be used as indexes into the mode_list[] table (zero is an
+ * invalid mode number, so this indexing must be offset by 1).
+ */
+ af->AvailableModes = available_modes;
+
+ /* driver attributes (see definitions in vbeaf.h) */
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer |
+ afHaveAccel2D);
+ af->Attributes |= afHaveHWCursor;
+
+ if (linear_addr)
+ af->Attributes |= afHaveLinearBuffer;
+
+ /* banked memory size and location: zero if not supported */
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ /* linear framebuffer size and location: zero if not supported */
+ if (linear_addr) {
+ af->LinearSize = af_memory/1024;
+ af->LinearBasePtr = linear_addr;
+ }
+ else {
+ af->LinearSize = 0;
+ af->LinearBasePtr = 0;
+ }
+
+ /* list which ports we are going to access (only needed under Linux) */
+ af->IOPortsTable = ports_table;
+
+ /* list physical memory regions that we need to access (zero for none) */
+ for (i=0; i<4; i++) {
+ af->IOMemoryBase[i] = 0;
+ af->IOMemoryLen[i] = 0;
+ }
+
+#ifndef DISABLE_MMIO
+ switch (detect_info[cir_card].family) {
+ case 0:
+ /* 5426, 5428 do not support MMIO */
+ break;
+ case 1:
+ /* MMIO for 5429 -- could we support this card's linear framebuffer?? */
+ af->IOMemoryBase[0] = 0xb8000;
+ af->IOMemoryLen[0] = 256;
+ break;
+ case 2:
+ case 5:
+ /* 5430,5436,5440,5446 */
+ if (linear_addr)
+ af->IOMemoryBase[0] = linear_addr+4*1024*1024-256;
+ else
+ af->IOMemoryBase[0] = 0xb8000;
+ af->IOMemoryLen[0] = 256;
+ break;
+ case 3:
+ case 4:
+ /* 5434 only allows MMIO at 0xb8000*/
+ af->IOMemoryBase[0] = 0xb8000;
+ af->IOMemoryLen[0] = 256;
+ break;
+ case 6:
+ /* 5480 */
+ /* if (linear_addr&&bus_type) {
+ regs.x.ax = 0xB102;
+ regs.x.bx=bus_type;
+ if (regs.h.ah)
+ goto pcinotfound;
+ regs.x.ax = 0xB102;
+ regs.x.cx = detect_info[cir_card].pcinum;
+ regs.x.dx = CIRRUS_PCI_VENDOR_ID;
+ regs.x.di = 32;
+ rm_int(0x1A, ®s);
+ if (regs.h.al) //should never occur
+ af->IOMemoryBase[0] = 0xb8000;
+ else
+ af->IOMemoryBase[0] = regs.d.ecx;
+ } else*/
+ af->IOMemoryBase[0] = 0xb8000;
+ af->IOMemoryLen[0] = 256;
+ break;
+ }
+#endif
+
+ /* driver state variables (initialised later during the mode set) */
+ af->BufferEndX = 0;
+ af->BufferEndY = 0;
+ af->OriginOffset = 0;
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+
+ /* relocatable bank switcher (not required by Allgero) */
+ af->SetBank32 = SetBank32;
+ af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
+
+ /* extension functions */
+ af->SupplementalExt = ExtStub;
+
+ /* device driver functions */
+ 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->EnableStereoMode = NULL;
+ af->SetPaletteData = SetPaletteData;
+ af->SetGammaCorrectData = NULL;
+ af->SetBank = SetBank;
+
+ /* hardware cursor functions (not supported: not used by Allegro) */
+ af->SetCursor = SetCursor;
+ af->SetCursorPos = SetCursorPos;
+ af->SetCursorColor = SetCursorColor;
+ af->ShowCursor = ShowCursor;
+ /* on some cards the CPU cannot access the framebuffer while it is in
+ * hardware drawing mode. If this is the case, you should fill in these
+ * functions with routines to switch in and out of the accelerator mode.
+ * The application will call EnableDirectAccess() whenever it is about
+ * to write to the framebuffer directly, and DisableDirectAccess()
+ * before it calls any hardware drawing routines. If this arbitration is
+ * not required, leave these routines as NULL.
+ */
+ af->EnableDirectAccess = NULL;
+ af->DisableDirectAccess = NULL;
+
+ /* sets the hardware drawing mode (solid, XOR, etc). Required. */
+ af->SetMix = SetMix;
+
+ /* pattern download functions. May be NULL if patterns not supported */
+ af->Set8x8MonoPattern = Set8x8MonoPattern;
+ af->Set8x8ColorPattern = Set8x8ColorPattern;
+ af->Use8x8ColorPattern = Use8x8ColorPattern;
+
+ /* not supported: not used by Allegro */
+ af->DrawScanList = NULL;
+ af->DrawPattScanList = NULL;
+ af->DrawColorPattScanList = NULL;
+
+ /* not supported: not used by Allegro */
+ af->DrawLine = NULL;
+ af->DrawStippleLine = NULL;
+ af->DrawTrap = NULL;
+ af->DrawTri = NULL;
+ af->DrawQuad = NULL;
+
+ af->BitBltLin = NULL;
+ af->BitBltBM = NULL;
+
+ af->PutMonoImageLin = NULL;
+ af->PutMonoImageBM = NULL;
+
+ /* not supported: not used by Allegro */
+ af->SetLineStipple = NULL;
+ af->SetLineStippleCount = NULL;
+
+ /* not supported. There really isn't much point in this function because
+ * a lot of hardware can't do clipping at all, and even when it can there
+ * are usually problems with very large or negative coordinates. This
+ * means that a software clip is still required, so you may as well
+ * ignore this routine.
+ */
+ af->SetClipRect = NULL;
+
+ af->SrcTransBltLin = NULL;
+ af->SrcTransBltBM = NULL;
+ af->DstTransBlt = NULL;
+ af->DstTransBltSys = NULL;
+ af->DstTransBltLin = NULL;
+ af->DstTransBltBM = NULL;
+ af->StretchBlt = NULL;
+ af->StretchBltSys = NULL;
+ af->StretchBltLin = NULL;
+ af->StretchBltBM = NULL;
+ af->SrcTransStretchBlt = NULL;
+ af->SrcTransStretchBltSys = NULL;
+ af->SrcTransStretchBltLin = NULL;
+ af->SrcTransStretchBltBM = NULL;
+ af->DstTransStretchBlt = NULL;
+ af->DstTransStretchBltSys = NULL;
+ af->DstTransStretchBltLin = NULL;
+ af->DstTransStretchBltBM = NULL;
+ af->SetVideoInput = NULL;
+ af->SetVideoOutput = NULL;
+ af->StartVideoFrame = NULL;
+ af->EndVideoFrame = NULL;
+
+ SetupFuncPtr8(af);
+ 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)
+{
+ if (cir_card==-1)
+ return -1;
+ else
+ return 0;
+}
+
+
+
+/* FreeBEX:
+ * Returns an interface structure for the requested FreeBE/AF extension.
+ */
+void *FreeBEX(AF_DRIVER *af, unsigned long id)
+{
+ switch (id) {
+
+ 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)
+{
+ _GFX_MODE_INFO *info;
+ int i;
+
+ if ((mode <= 0) || (mode > num_modes))
+ return -1;
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ info=&mode_list[mode-1];
+ /* copy data across from our stored list of mode attributes */
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer |
+ afHaveAccel2D);
+ modeInfo->Attributes |= afHaveHWCursor;
+
+ if (linear_addr)
+ modeInfo->Attributes |= afHaveLinearBuffer;
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ /* available pages of video memory */
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->bpl * info->h);
+
+ /* maximum virtual scanline length in both bytes and pixels. How wide
+ * this can go will very much depend on the card: 1024 is pretty safe
+ * on anything, but you will want to allow larger limits if the card
+ * is capable of them.
+ */
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+
+ /* for banked video modes, fill in these variables: */
+ modeInfo->BytesPerScanLine = info->bpl;
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+ switch (info->bpp) {
+ case 8:
+ break;
+ case 15:
+ modeInfo->RedMaskSize = 5;
+ modeInfo->RedFieldPosition = 10;
+ modeInfo->GreenMaskSize = 5;
+ modeInfo->GreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = 5;
+ modeInfo->RsvdMaskSize = 1;
+ modeInfo->RsvdFieldPosition = 15;
+ break;
+ case 16:
+ modeInfo->RedMaskSize = 5;
+ modeInfo->RedFieldPosition = 11;
+ modeInfo->GreenMaskSize = 6;
+ modeInfo->GreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = 5;
+ break;
+ case 24:
+ modeInfo->RedMaskSize = 8;
+ modeInfo->RedFieldPosition = 16;
+ modeInfo->GreenMaskSize = 8;
+ modeInfo->GreenFieldPosition = 8;
+ modeInfo->BlueMaskSize = 8;
+ break;
+ case 32:
+ modeInfo->RedMaskSize = 8;
+ modeInfo->RedFieldPosition = 16;
+ modeInfo->GreenMaskSize = 8;
+ modeInfo->GreenFieldPosition = 8;
+ modeInfo->BlueMaskSize = 8;
+ modeInfo->RsvdMaskSize = 8;
+ modeInfo->RsvdFieldPosition = 24;
+ break;
+ }
+
+ /* for linear video modes, fill in these variables: */
+ modeInfo->LinBytesPerScanLine = modeInfo->BytesPerScanLine;
+ modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
+ modeInfo->LinRedMaskSize = modeInfo->RedMaskSize;
+ modeInfo->LinRedFieldPosition = modeInfo->RedFieldPosition;
+ modeInfo->LinGreenMaskSize = modeInfo->GreenMaskSize;
+ modeInfo->LinGreenFieldPosition = modeInfo->GreenFieldPosition;
+ modeInfo->LinBlueMaskSize = modeInfo->BlueMaskSize;
+ modeInfo->LinBlueFieldPosition = modeInfo->BlueFieldPosition;
+ modeInfo->LinRsvdMaskSize = modeInfo->RsvdMaskSize;
+ modeInfo->LinRsvdFieldPosition = modeInfo->RsvdFieldPosition;
+
+ /* 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;
+}
+
+int set_width(int width)
+{
+ width>>=3;
+ if (width<512) {
+ write_vga_register(_crtc, 0x13, width & 0xFF);
+ alter_vga_register(_crtc, 0x1B, 16, (width >> 4)&16);
+ return width<<3;
+ } else
+ return af_width;
+}
+
+/* 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)
+{
+ int linear = ((mode & 0x4000) != 0);
+ int noclear = ((mode & 0x8000) != 0);
+ int i;
+ long available_vram;
+ long used_vram;
+ unsigned char *p;
+ _GFX_MODE_INFO *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo */
+ if (mode & 0x400)
+ return -1;
+
+ /* mask off the other flag bits */
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > num_modes))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ r.x.ax=info->num;/*set the mode through bios function 0*/
+ if (noclear) r.x.ax|=0x80;
+ rm_int(0x10,&r);
+ if (info->bpp==15) {
+ inportb(0x3c6); //to access hidden dac register on cirruses 4
+ inportb(0x3c6); // consecutive reads must be perforamed
+ inportb(0x3c6);
+ inportb(0x3c6);
+ mode=inportb(0x3c6);
+ mode&=0xef; // mask out bit 4 which enables extended 15 bit modes
+ // (bit 15 of color data determines if data is regular 15bit color or
+ // palette index)
+ inportb(0x3c6); //to access hidden dac register on cirruses 4
+ inportb(0x3c6); // consecutive reads must be perforamed
+ inportb(0x3c6);
+ inportb(0x3c6);
+ outportb(0x3c6,mode);
+ }
+ /* 16k banks, single page, disable extensions */
+ alter_vga_register(0x3CE, 0xB, 0x21, 0x20);
+ /* reject the linear flag if the mode doesn't support it */
+ if (linear && linear_addr) {
+ alter_vga_register(0x3c4,0x7,0xf0,0xf0);
+ } else
+ linear = 0;
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX*BYTES_PER_PIXEL(info->bpp) > info->bpl) {
+ *bytesPerLine = set_width(virtualX*BYTES_PER_PIXEL(info->bpp));
+ }
+ else
+ *bytesPerLine = info->bpl;
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_linear = linear;
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_bank = -1;
+
+ /* return framebuffer dimensions to the application */
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ af_fore_mix = AF_REPLACE_MIX;
+ af_back_mix = AF_FORE_MIX;
+
+ cir_bpp=BYTES_PER_PIXEL(af_bpp);
+
+ CIR_SRCPITCH(af_width);
+ CIR_DSTPITCH(af_width);
+ if (af->IOMemoryBase[0]) {
+ // setup MMIO
+ if (af_linear)
+ alter_vga_register(0x3c4,0x17,0x44,0x44);
+ else
+ alter_vga_register(0x3c4,0x17,0x44,0x04);
+ af_mmio=(unsigned long)af->IOMemMaps[0];
+ switch (af_bpp) {
+ case 8:
+ cir_pixmode=CIR_BLT_PIX8;
+ SetupFuncPtr8MMIO(af);
+ break;
+ case 15:
+ case 16:
+ cir_pixmode=CIR_BLT_PIX16;
+ SetupFuncPtr16MMIO(af);
+ break;
+ case 24:
+ cir_pixmode=CIR_BLT_PIX24;
+ SetupFuncPtr24MMIO(af);
+ break;
+ case 32:
+ cir_pixmode=CIR_BLT_PIX32;
+ SetupFuncPtr32MMIO(af);
+ break;
+ }
+
+ } else {
+ switch (af_bpp) {
+ case 8:
+ cir_pixmode=CIR_BLT_PIX8;
+ SetupFuncPtr8(af);
+ break;
+ case 15:
+ case 16:
+ cir_pixmode=CIR_BLT_PIX16;
+ SetupFuncPtr16(af);
+ break;
+ case 24:
+ cir_pixmode=CIR_BLT_PIX24;
+ SetupFuncPtr24(af);
+ break;
+ case 32:
+ cir_pixmode=CIR_BLT_PIX32;
+ SetupFuncPtr32(af);
+ break;
+ }
+ }
+ cir_offmono=af_memory-MONOPATTSTART;
+ cir_offscreen=af_memory-SOLIDPATTSTART;
+ cir_offcolor=af_memory-COLPATTSTART;
+ cir_bltmode=CIR_BLT_PATT|CIR_BLT_COLEXP|cir_pixmode;
+ cir_bltrop=CIR_ROP_COPY;
+ af_last_bank=(af_memory)/64/1024-1;
+ if (af_linear) {
+ p=af->LinearMem+af_memory-SOLIDPATTSTART;
+ for (i=0;i<8;i++)
+ p[i]=0xff;
+ } else {
+ p=af->BankedMem+DISPLACEMENT-SOLIDPATTSTART;
+ SetBank(af,af_last_bank);
+ for (i=0;i<8;i++)
+ p[i]=0xff;
+ }
+ return 0;
+}
+
diff --git a/cirrus54/drvhdr.c b/cirrus54/drvhdr.c
new file mode 100644
index 0000000..adbdf59
--- /dev/null
+++ b/cirrus54/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF Cirrus 54xx driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/cirrus54/notes.txt b/cirrus54/notes.txt
new file mode 100644
index 0000000..cdd7a8e
--- /dev/null
+++ b/cirrus54/notes.txt
@@ -0,0 +1,58 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ Cirrus 54x driver implementation notes.
+
+Pattern fills may be improved quite a lot for cards which supports starting
+on different place of pattern than upper left corner (now I always assume
+accelerator can't do that so whenever upper left corner changes I change the
+pattern). I also don't understand the notation of raster operations cirrus
+supports and so SetMix isn't probably implemented properly.
+
+Because of lack of precise specification of right input data to functions, some
+of them may be implemented wrong.
+
+Optimization with -O3 helps a bit, also port accesses are on RING 3 quite slow
+so checking is the content of registers changed helped quite a bit. I expect
+there might be quite a lot of problem with newer cirruses now, definitely
+should work with 5426,5428,7541 and 7543.
+
+***Note: Now also tested with a 5446 (rev A) and modified to work
+ (Keir Fraser, email: kaf24@cam.ac.uk)
+ I have had some problems with the memory-mapped IO, specifically when the
+ registers are mapped to low memory (0xb8000). If you are having problems
+ getting the driver to work, you can disable MMIO by uncommenting the
+ DISABLE_MMIO line at the top of driver.c. You should also contact me at
+ the email address given above to look for a more permanent solution!
+
+Supported functions:
+
+ WaitTillIdle()
+ SetMix()
+ Set8x8MonoPattern()
+ Set8x8ColorPattern()
+ Use8x8ColorPattern()
+ DrawScan()
+ DrawPattScan()
+ DrawColorPattScan()
+ DrawRect()
+ DrawPattRect()
+ DrawColorPattRect()
+ BitBlt()
+ SrcTransBlt()
+ SetCursor
+ SetCursorPos
+ SetCursorColor
+ ShowCursor
+ SrcTransBltSys()
+ BitBltSys()
+ PutMonoImage()
+
+Author: Michal Mertl (Czech Republic)
+Email: mime@eunet.cz
diff --git a/drv.ld b/drv.ld
new file mode 100644
index 0000000..ceb023f
--- /dev/null
+++ b/drv.ld
@@ -0,0 +1,12 @@
+OUTPUT_FORMAT("coff-go32")
+
+FORCE_COMMON_ALLOCATION
+
+SECTIONS {
+ .text 0 : {
+ *(.text)
+ *(.data)
+ *(.bss)
+ *(COMMON)
+ }
+}
diff --git a/drvgen.c b/drvgen.c
new file mode 100644
index 0000000..7bf64f5
--- /dev/null
+++ b/drvgen.c
@@ -0,0 +1,220 @@
+/* This is a modified DXEGEN.C. Here are the original DXEGEN.C's
+ copyright notices:
+
+ Copyright (C) 1995 Charles Sandmann (sandmann@clio.rice.edu)
+ This software may be freely distributed with above copyright, no warranty.
+ Based on code by DJ Delorie, it's really his, enhanced, bugs fixed. */
+
+#include
+#include
+#include
+#include
+#include "vbeaf.h"
+
+extern AF_DRIVER drvhdr;
+
+void exit_cleanup(void)
+{
+ remove("drv__tmp.o");
+}
+
+int main(int argc, char **argv)
+{
+ int errors = 0;
+ unsigned bss_start = 0;
+ FILHDR fh;
+ FILE *input_f, *output_f;
+ SCNHDR sc;
+ char *data, *strings;
+ SYMENT *sym;
+ RELOC *relocs;
+ int strsz, i;
+ long init1_offset,init2_offset,init3_offset,element_size,nrelocs,vbe_size;
+
+ if (argc < 6)
+ {
+ printf("Usage: drvgen output.drv oemext pnpinit initdrv input.o [input2.o ... -lgcc -lc]\n");
+ return 1;
+ }
+
+ input_f = fopen(argv[5], "rb");
+ if (!input_f)
+ {
+ perror(argv[5]);
+ return 1;
+ }
+
+ fread(&fh, 1, FILHSZ, input_f);
+ if (fh.f_nscns != 1 || argc > 5)
+ {
+ char command[1024];
+ fclose(input_f);
+
+ strcpy(command,"ld -X -S -r -o drv__tmp.o -L");
+ strcat(command,getenv("DJDIR"));
+ strcat(command,"/lib ");
+ for(i=5;argv[i];i++) {
+ strcat(command,argv[i]);
+ strcat(command," ");
+ }
+ strcat(command,"-T ../drv.ld");
+
+ printf("%s\n",command);
+ i = system(command);
+ if(i)
+ return i;
+
+ input_f = fopen("drv__tmp.o", "rb");
+ if (!input_f)
+ {
+ perror(argv[5]);
+ return 1;
+ } else
+ atexit(exit_cleanup);
+
+ fread(&fh, 1, FILHSZ, input_f);
+ if (fh.f_nscns != 1) {
+ printf("Error: input file has more than one section; use -M for map\n");
+ return 1;
+ }
+ }
+
+ fseek(input_f, fh.f_opthdr, 1);
+ fread(&sc, 1, SCNHSZ, input_f);
+
+ init1_offset = -1;
+ init2_offset = -1;
+ init3_offset = -1;
+ element_size = sc.s_size;
+ nrelocs = sc.s_nreloc;
+
+ data = malloc(sc.s_size);
+ fseek(input_f, sc.s_scnptr, 0);
+ fread(data, 1, sc.s_size, input_f);
+
+ sym = malloc(sizeof(SYMENT)*fh.f_nsyms);
+ fseek(input_f, fh.f_symptr, 0);
+ fread(sym, fh.f_nsyms, SYMESZ, input_f);
+ fread(&strsz, 1, 4, input_f);
+ strings = malloc(strsz);
+ fread(strings+4, 1, strsz-4, input_f);
+ strings[0] = 0;
+ for (i=0; i<(int)fh.f_nsyms; i++)
+ {
+ char tmp[9], *name;
+ if (sym[i].e.e.e_zeroes)
+ {
+ memcpy(tmp, sym[i].e.e_name, 8);
+ tmp[8] = 0;
+ name = tmp;
+ }
+ else
+ name = strings + sym[i].e.e.e_offset;
+#if 0
+ printf("[%3d] 0x%08x 0x%04x 0x%04x %d %s\n",
+ i,
+ sym[i].e_value,
+ sym[i].e_scnum & 0xffff,
+ sym[i].e_sclass,
+ sym[i].e_numaux,
+ name
+ );
+#endif
+ if (sym[i].e_scnum == 0)
+ {
+ printf("Error: object contains unresolved external symbols (%s)\n", name);
+ errors ++;
+ }
+ if (strncmp(name, argv[2], strlen(argv[2])) == 0)
+ {
+ if (init1_offset != -1)
+ {
+ printf("Error: multiple symbols that start with %s (%s)!\n", argv[2], name);
+ errors++;
+ }
+ init1_offset = sym[i].e_value;
+ } else if (strncmp(name, argv[3], strlen(argv[3])) == 0)
+ {
+ if (init2_offset != -1)
+ {
+ printf("Error: multiple symbols that start with %s (%s)!\n", argv[3], name);
+ errors++;
+ }
+ init2_offset = sym[i].e_value;
+ } else if (strncmp(name, argv[4], strlen(argv[4])) == 0)
+ {
+ if (init3_offset != -1)
+ {
+ printf("Error: multiple symbols that start with %s (%s)!\n", argv[4], name);
+ errors++;
+ }
+ init3_offset = sym[i].e_value;
+ } else if (strcmp(name, ".bss") == 0 && !bss_start) {
+ bss_start = sym[i].e_value;
+/* printf("bss_start 0x%x\n",bss_start); */
+ memset(data+bss_start, 0, sc.s_size - bss_start);
+ }
+ i += sym[i].e_numaux;
+ }
+
+ if (init1_offset == -1)
+ {
+ printf("Error: symbol %s not found!\n", argv[2]);
+ errors++;
+ }
+
+ if (init2_offset == -1)
+ {
+ printf("Error: symbol %s not found!\n", argv[3]);
+ errors++;
+ }
+
+ if (init3_offset == -1)
+ {
+ printf("Error: symbol %s not found!\n", argv[4]);
+ errors++;
+ }
+
+ relocs = malloc(sizeof(RELOC)*sc.s_nreloc);
+ fseek(input_f, sc.s_relptr, 0);
+ fread(relocs, sc.s_nreloc, RELSZ, input_f);
+#if 0
+ for (i=0; i
+@
+@FreeBE/AF - the free VBE/AF driver project
+@
+@
+@startoutput readme.txt
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ The free VBE/AF driver project, version 1.2
+
+ http://www.talula.demon.co.uk/freebe/
+
+
+ "The nice thing about standards is that
+ there are so many of them to choose from."
+@
+
+
+
+@heading
+Introduction
+
+ VBE/AF is a low level driver interface for accessing graphics hardware.
+ It provides all the same features as VESA 3.0 (access to linear
+ framebuffer video memory, high speed protected mode bank switching, page
+ flipping, hardware scrolling, etc), and adds the ability to use 2D
+ hardware acceleration in an efficient and portable manner. An /AF driver
+ is provided as a disk file (vbeaf.drv), and contains clean 32 bit machine
+ code which can be called directly by a C program. If implemented
+ correctly, these drivers have the potential to be binary portable across
+ multiple operating systems, so the same driver file can be used from DOS,
+ Windows, Linux, etc.
+
+ FreeBE/AF is an attempt to implement free VBE/AF drivers on as many cards
+ as possible. This idea came about on the Allegro mailing list, due to the
+ need for a dynamically loadable driver structure that could support
+ hardware acceleration. VBE/AF seemed to fit the bill, and Allegro already
+ had support for the SciTech drivers, so it seemed like a good idea to
+ adopt this format for ourselves. The primary goal is to make these
+ drivers work with Allegro, so the emphasis will be on implementing the
+ functions that Allegro actually uses, but we encourage other developers
+ to join us in taking advantage of this excellent driver architecture.
+
+ This project currently provides fully accelerated drivers for a handful
+ of chipsets, plus a number of dumb framebuffer implementations based on
+ the video drivers from older versions of the Allegro library. It has also
+ defined a few extensions to the stock VBE/AF API, which allow Allegro
+ programs to use these drivers in a true protected mode environment
+ without having to resort to the nearptr hack, and provide a number of
+ hook functions that will be needed to remain compatible with future
+ generations of the SciTech drivers.
+
+ The current status of the VBE/AF standard is somewhat confused. It was
+ designed by SciTech Software (http://www.scitechsoft.com/), who provide
+ commercial VBE/AF drivers for a wide range of cards as part of their
+ Display Doctor package. It was originally going to be released as a VESA
+ standard, but the VESA people seriously messed this up by charging
+ exorbitant sums of $$$ for copies of the spec. As a result, very few
+ people bothered to support these drivers, and the FreeBE/AF project was
+ only made possible by the information available in the SciTech MGL
+ library source code, and the helpfulness of Kendall Bennett (the designer
+ of the spec) himself. Unfortunately SciTech have now abandoned VBE/AF
+ themselves, replacing it with an equivalent but non-public API called
+ Nucleus, which is only available under NDA. SciTech will continue to
+ provide VBE/AF drivers for the cards which they already support, but
+ will not adding any new ones in the future, so this project is now the
+ only active source of VBE/AF driver implementations.
+
+ At present, the Allegro (http://www.talula.demon.co.uk/allegro/) and MGL
+ (http://www.scitechsoft.com) libraries are the only major packages which
+ can take advantage of accelerated VBE/AF drivers. As such, this project
+ is starting to look more like a implementation of video drivers
+ specifically for the Allegro library, rather than a potential
+ industry-wide standard :-) But it doesn't have to be this way! VBE/AF is
+ technically an excellent design: efficient, easy to write and use, and
+ highly portable. If you are writing graphics code, and getting frustrated
+ by the many limitiations imposed by VESA, why not think about using
+ VBE/AF instead? Even better, if you have a card that our project doesn't
+ yet support, why not add a new driver for it? This can be a lot of fun,
+ and we would be delighted to offer any help or advice that you might need.
+
+
+
+@endoutput readme.txt
+@heading
+Usage
+
+ Each driver is located in a different subdirectory. Run "make" to compile
+ them, choose the one you want, copy the vbeaf.drv file from this
+ directory to c:\, and you are ready to go!
+
+ The stub directory contains a generic non-accelerated VBE/AF driver. This
+ is not useful in any way, because it simply sits on top of your existing
+ VESA driver and emulates a few "hardware" drawing operations with very
+ slow software implementations. The stub is intended as a starting point
+ for people who want to make drivers for a specific card, and should not
+ be used directly.
+
+ To recompile FreeBE/AF, you need a working copy of djgpp. Run "make" to
+ build all the available drivers, or "make dir/vbeaf.drv" to compile a
+ specific driver (replacing {dir} with the directory name, eg. "make
+ stub/vbeaf.drv"). To build the install.exe program for a binary
+ distribution, run "make all" (this requires you to have the Allegro
+ library installed, and the allegro/tools/ directory in your path). This
+ documentation is converted from the custom ._tx format into ASCII and
+ HTML by the Allegro makedoc program: run "make docs" to do this, after
+ putting the makedoc utility somewhere in your path.
+
+ FreeBE/AF only supports the VBE/AF 2.0 API. It is not backward compatible
+ with the assembler VBE/AF 1.0 interface, and programs that try to use
+ those obsolete functions will not work correctly.
+
+
+
+@startoutput readme.txt
+@heading
+Supported Hardware
+
+ Not all VBE/AF drivers provide the complete set of possible features.
+ Some may be written in a 100% clean and portable manner, allowing them to
+ be used on any platform, but others make use of the video BIOS in order
+ to set the initial video mode: this makes them a lot easier to write, but
+ means that it can only be used under DOS. Some of the drivers, in
+ particular the ones based on the old Allegro library chipset support,
+ don't support any hardware accelerated drawing at all: these are still
+ usefull because they provide high speed protected mode bank switching and
+ can work around the bugs in some manufacturer's VESA implementations, but
+ are obviously not nearly as cool as a fully accelerated driver.
+
+ This table lists the currently available FreeBE/AF drivers, and what
+ features they each provide:
+
+ ATI 18800/28800 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ ATI mach64 |
+ Uses BIOS |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Avance Logic ALG-2101, ALG-2201, ALG-2228, ALG-2301, ALG-2302 |
+ Uses BIOS |
+ Banked modes only |
+ No FreeBE/AF extensions |
+ Dumb framebuffer |
+
+ Cirrus 54xx (not 546x). Should be ok with 5426, 5428, 7541, 7543 |
+ Uses BIOS |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Matrox Millenium, Mystique, Millenium II |
+ Uses BIOS |
+ Banked and linear modes |
+ Supports farptr and config extensions |
+ Hardware accelerated |
+
+ NVidia Riva 128, TNT. Conflicts with Windows! |
+ 100% portable |
+ Banked and linear modes |
+ Supports config extension |
+ Hardware accelerated |
+
+ Paradise |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ S3 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Hardware accelerated |
+
+ Trident TGUI 9440. Doesn't work under Windows! |
+ 100% portable |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Trident |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ Tseng ET3000/ET4000/ET6000 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ Video-7 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ stub driver (for testing and development purposes only) |
+ Uses BIOS |
+ Banked and linear modes |
+ Supports farptr and config extensions |
+ Slow software emulation of hardware drawing functions |
+
+
+
+@endoutput readme.txt
+@heading
+Contributing
+
+ If you want to add a new driver, follow these steps:
+
+ md cardname
+ copy stub\*.* cardname
+ edit makefile
+ { add a new entry to the DRIVERS variable at the top of the file }
+ cd cardname
+ edit drvhdr.c
+ { replace "stub driver implementation" with your driver name }
+ edit driver.c
+ { fill in the blanks, replacing the VESA calls with chipset-specific }
+ { code, and fleshing out the accelerated drawing functions }
+ edit notes.txt
+ { describe anything interesting about your driver, most importantly }
+ { listing what drawing functions it supports in hardware }
+ cd..
+ done!
+
+ The makefile requires each driver to provide a drvhdr.c file, which will
+ be linked into the drvgen.exe utility and used to generate the VBE/AF
+ header. You must also provide a notes.txt, which will be displayed by the
+ installation program, but everything else is entirely up to you. Any C
+ source files placed into your driver directory will automatically be
+ compiled and linked into the driver binary, so you can organise your code
+ in whatever style you prefer.
+
+ Because the VBE/AF drivers are output as relocatable binary modules, they
+ cannot use any C library functions. There are a few utility functions in
+ helper.c, but these will not work on any platforms other than DOS+DPMI,
+ so it would be better to avoid using them if you can manage without.
+
+ A great deal of hardware information can be found in the VGADOC package
+ (ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/vgadoc4b.zip) and the
+ XFree86 sources (http://www.xfree86.org/). If this isn't enough, try
+ asking the manufacturer for more details.
+
+
+
+@heading
+Files
+
+ freebe.txt - ASCII format documentation
+ freebe.html - HTML format documentation
+ freebe._tx - custom format documentation source file
+ makefile - script for building the drivers
+ vbeaf.h - VBE/AF structures and constants
+ start.s - driver relocation code
+ helper.c - debugging trace printf() and VESA helper routines
+ drvgen.c - modified version of DXEGEN, for building vbeaf.drv
+ drv.ld - linker script
+ install.c - installation program for binary distributions
+
+ stub/vbeaf.drv - example driver, using VESA to access the hardware
+ stub/driver.c - main implementation file for the example driver
+ stub/drvhdr.c - VBE/AF header structure for the example driver
+ stub/notes.txt - more information about the example driver
+
+ ati/ - ATI 18800/28800 driver, based on old Allegro code
+ avance/ - Avance Logic driver, by George Foot
+ cirrus54/ - Cirrus 54x driver, by Michal Mertl
+ mach64/ - ATI mach64 driver, by Ove Kaaven
+ matrox/ - Matrox driver, by Shawn Hargreaves
+ nvidia/ - NVidia driver, by Shawn Hargreaves
+ paradise/ - Paradise driver, based on old Allegro code
+ s3/ - S3 driver, by Michal Stencl
+ tgui/ - Trident TGUI 9440 driver, by Salvador Eduardo Tropea
+ trident/ - Trident driver, based on old Allegro code
+ tseng/ - Tseng driver, based on old Allegro code
+ video7/ - Video-7 driver, based on old Allegro code
+
+
+
+@startoutput readme.txt
+@heading
+Copyright
+
+ As the name implies, FreeBE/AF is free. Both the driver binaries and
+ sources may be distributed and modified without restriction. If you find
+ any of this stuff useful, the best way to repay us is by writing a new
+ driver for a card that isn't currently supported.
+
+ Disclaimer: no warranty is provided with this software. We are not to be
+ held liable if it fries your monitor, eats your graphics card, or roasts
+ your motherboard.
+
+
+
+@heading
+Credits
+
+ The DRVGEN utility is based on the djgpp DXEGEN system, by Charles
+ Sandmann (sandmann@clio.rice.edu) and DJ Delorie (dj@delorie.com).
+
+ Linking/relocation system and ATI mach64 driver by Ove Kaaven
+ (ovek@arcticnet.no).
+
+ VBE/AF framework, stub driver, Matrox driver, NVidia driver, most of the
+ old Allegro chipset drivers, conversion from Allegro to VBE/AF format,
+ and installation program by Shawn Hargreaves (shawn@talula.demon.co.uk).
+
+ Cirrus 54x driver by Michal Mertl (mime@eunet.cz).
+
+ Trident TGUI 9440 driver by Salvador Eduardo Tropea (set-soft@usa.net).
+
+ Avance Logic driver by George Foot (george.foot@merton.oxford.ac.uk).
+
+ Fixes to the Cirrus 5446 MMIO routines by Keir Fraser (kaf24@cam.ac.uk).
+
+ Tseng ET6000 support by Ben Chauveau (bendomc@worldnet.fr).
+
+ Paradise driver by Francois Charton (deef@pobox.oleane.com).
+
+ Tseng ET4000 15/24 bit support by Marco Campinoti (marco@etruscan.li.it).
+
+ Trident driver improved by Mark Habersack (grendel@ananke.amu.edu.pl).
+
+ Video-7 fixes by Markus Oberhumer (markus.oberhumer@jk.uni-linz.ac.at).
+
+ S3 driver improved by Michael Bukin (M.A.Bukin@inp.nsk.su).
+
+ Video-7 driver by Peter Monks (Peter_Monks@australia.notes.pw.com).
+
+ S3 hardware acceleration by Michal Stencl (stenclpmd@ba.telecom.sk).
+
+ Website logo by Colin Walsh (cwalsh@nf.sympatico.ca).
+
+ More graphics hardware support by [insert your name here] :-)
+
+ VBE/AF itself is the brainchild of SciTech software, and in particular
+ Kendall Bennett (KendallB@scitechsoft.com).
+
+ The Video Electronics Standards Association does _not_ deserve any
+ mention here. The absurd prices they charge for copies of the /AF
+ specification have prevented it from being widely supported, and I think
+ this is a great pity. Long live freedom!
+
+
+
+@heading
+History
+
+ 30 March, 1998 - v0.1.
+ First public release, containing an example driver implementation that
+ runs on top of VESA.
+
+ 31 March, 1998 - v0.11.
+ Added support for multi-buffered modes.
+
+ 5 April, 1998 - v0.2.
+ Added an accelerated Matrox driver.
+
+ 8 April, 1998 - v0.3.
+ Added accelerated drivers for ATI mach64 and Cirrus 54x cards, plus
+ minor updates to the Matrox driver.
+
+ 12 April, 1998 - v0.4.
+ Proper installation program, more drawing functions implemented by the
+ stub and Matrox drivers, improved ATI driver, compiled with PGCC for a
+ 5% speed boost.
+
+ 26 April, 1998 - v0.5.
+ More accelerated features in the Cirrus and ATI drivers. Fixed bugs in
+ the Matrox driver. Added an option to disable hardware emulation in
+ the stub driver, which produces a non-accelerated, dumb framebuffer
+ implementation. The init code will now politely fail any programs that
+ try to use VBE/AF 1.0 functions, rather than just crashing.
+
+ 10 June, 1998 - v0.6.
+ Fixed scrolling problem on Millenium cards.
+
+ 1 November, 1998 - v0.7.
+ Added drivers for Trident TGUI 9440 and Avance Logic cards, and
+ improved the build process.
+
+ 14 December, 1998 - v0.8.
+ Bugfixes to the Matrox Millenium II and Cirrus drivers. Converted all
+ the old Allegro library chipset drivers into non-accelerated VBE/AF
+ format, adding support for ATI 18800/28800, Paradise, S3, Trident,
+ Tseng ET3000/ET4000/ET6000, and Video-7 boards. Designed and
+ implemented an API extension mechanism, providing the ability to use
+ these drivers in a true protected mode environment, a more rational
+ relocation scheme, and various hooks that will later be needed for
+ supporting the SciTech Nucleus drivers.
+
+ 20 December, 1998 - v0.9.
+ Bugfixes. Added a config mechanism, allowing the install program to
+ optionally disable some features of a driver.
+
+ 3 January, 1999 - v1.0
+ Bugfixes.
+
+ 27 March, 1999 - v1.1
+ Added acceleration support to the S3 driver, plus some bugfixes.
+
+ 27 June, 1999 - v1.2
+ Added driver for NVidia cards. Improved the PCI bus scanning code to
+ know about bridges to secondary devices (so it can locate AGP cards).
+ Minor bugfix to the Mach64 driver (it was using the wrong clip rect
+ for scrolling displays). Minor bugfix to the Matrox driver (it was
+ setting the wrong background color for the hardware cursor).
diff --git a/freebe.html b/freebe.html
new file mode 100644
index 0000000..673dfef
--- /dev/null
+++ b/freebe.html
@@ -0,0 +1,411 @@
+
+
+FreeBE/AF - the free VBE/AF driver project
+
+
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ The free VBE/AF driver project, version 1.2
+
+ http://www.talula.demon.co.uk/freebe/
+
+
+ "The nice thing about standards is that
+ there are so many of them to choose from."
+
+
+
+
+
+
+ VBE/AF is a low level driver interface for accessing graphics hardware.
+ It provides all the same features as VESA 3.0 (access to linear
+ framebuffer video memory, high speed protected mode bank switching, page
+ flipping, hardware scrolling, etc), and adds the ability to use 2D
+ hardware acceleration in an efficient and portable manner. An /AF driver
+ is provided as a disk file (vbeaf.drv), and contains clean 32 bit machine
+ code which can be called directly by a C program. If implemented
+ correctly, these drivers have the potential to be binary portable across
+ multiple operating systems, so the same driver file can be used from DOS,
+ Windows, Linux, etc.
+
+ FreeBE/AF is an attempt to implement free VBE/AF drivers on as many cards
+ as possible. This idea came about on the Allegro mailing list, due to the
+ need for a dynamically loadable driver structure that could support
+ hardware acceleration. VBE/AF seemed to fit the bill, and Allegro already
+ had support for the SciTech drivers, so it seemed like a good idea to
+ adopt this format for ourselves. The primary goal is to make these
+ drivers work with Allegro, so the emphasis will be on implementing the
+ functions that Allegro actually uses, but we encourage other developers
+ to join us in taking advantage of this excellent driver architecture.
+
+ This project currently provides fully accelerated drivers for a handful
+ of chipsets, plus a number of dumb framebuffer implementations based on
+ the video drivers from older versions of the Allegro library. It has also
+ defined a few extensions to the stock VBE/AF API, which allow Allegro
+ programs to use these drivers in a true protected mode environment
+ without having to resort to the nearptr hack, and provide a number of
+ hook functions that will be needed to remain compatible with future
+ generations of the SciTech drivers.
+
+ The current status of the VBE/AF standard is somewhat confused. It was
+ designed by SciTech Software (http://www.scitechsoft.com/), who provide
+ commercial VBE/AF drivers for a wide range of cards as part of their
+ Display Doctor package. It was originally going to be released as a VESA
+ standard, but the VESA people seriously messed this up by charging
+ exorbitant sums of $$$ for copies of the spec. As a result, very few
+ people bothered to support these drivers, and the FreeBE/AF project was
+ only made possible by the information available in the SciTech MGL
+ library source code, and the helpfulness of Kendall Bennett (the designer
+ of the spec) himself. Unfortunately SciTech have now abandoned VBE/AF
+ themselves, replacing it with an equivalent but non-public API called
+ Nucleus, which is only available under NDA. SciTech will continue to
+ provide VBE/AF drivers for the cards which they already support, but
+ will not adding any new ones in the future, so this project is now the
+ only active source of VBE/AF driver implementations.
+
+ At present, the Allegro (http://www.talula.demon.co.uk/allegro/) and MGL
+ (http://www.scitechsoft.com) libraries are the only major packages which
+ can take advantage of accelerated VBE/AF drivers. As such, this project
+ is starting to look more like a implementation of video drivers
+ specifically for the Allegro library, rather than a potential
+ industry-wide standard :-) But it doesn't have to be this way! VBE/AF is
+ technically an excellent design: efficient, easy to write and use, and
+ highly portable. If you are writing graphics code, and getting frustrated
+ by the many limitiations imposed by VESA, why not think about using
+ VBE/AF instead? Even better, if you have a card that our project doesn't
+ yet support, why not add a new driver for it? This can be a lot of fun,
+ and we would be delighted to offer any help or advice that you might need.
+
+
+
+
+
+ Each driver is located in a different subdirectory. Run "make" to compile
+ them, choose the one you want, copy the vbeaf.drv file from this
+ directory to c:\, and you are ready to go!
+
+ The stub directory contains a generic non-accelerated VBE/AF driver. This
+ is not useful in any way, because it simply sits on top of your existing
+ VESA driver and emulates a few "hardware" drawing operations with very
+ slow software implementations. The stub is intended as a starting point
+ for people who want to make drivers for a specific card, and should not
+ be used directly.
+
+ To recompile FreeBE/AF, you need a working copy of djgpp. Run "make" to
+ build all the available drivers, or "make dir/vbeaf.drv" to compile a
+ specific driver (replacing {dir} with the directory name, eg. "make
+ stub/vbeaf.drv"). To build the install.exe program for a binary
+ distribution, run "make all" (this requires you to have the Allegro
+ library installed, and the allegro/tools/ directory in your path). This
+ documentation is converted from the custom ._tx format into ASCII and
+ HTML by the Allegro makedoc program: run "make docs" to do this, after
+ putting the makedoc utility somewhere in your path.
+
+ FreeBE/AF only supports the VBE/AF 2.0 API. It is not backward compatible
+ with the assembler VBE/AF 1.0 interface, and programs that try to use
+ those obsolete functions will not work correctly.
+
+
+
+
+
+ Not all VBE/AF drivers provide the complete set of possible features.
+ Some may be written in a 100% clean and portable manner, allowing them to
+ be used on any platform, but others make use of the video BIOS in order
+ to set the initial video mode: this makes them a lot easier to write, but
+ means that it can only be used under DOS. Some of the drivers, in
+ particular the ones based on the old Allegro library chipset support,
+ don't support any hardware accelerated drawing at all: these are still
+ usefull because they provide high speed protected mode bank switching and
+ can work around the bugs in some manufacturer's VESA implementations, but
+ are obviously not nearly as cool as a fully accelerated driver.
+
+ This table lists the currently available FreeBE/AF drivers, and what
+ features they each provide:
+
+ ATI 18800/28800 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ ATI mach64 |
+ Uses BIOS |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Avance Logic ALG-2101, ALG-2201, ALG-2228, ALG-2301, ALG-2302 |
+ Uses BIOS |
+ Banked modes only |
+ No FreeBE/AF extensions |
+ Dumb framebuffer |
+
+ Cirrus 54xx (not 546x). Should be ok with 5426, 5428, 7541, 7543 |
+ Uses BIOS |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Matrox Millenium, Mystique, Millenium II |
+ Uses BIOS |
+ Banked and linear modes |
+ Supports farptr and config extensions |
+ Hardware accelerated |
+
+ NVidia Riva 128, TNT. Conflicts with Windows! |
+ 100% portable |
+ Banked and linear modes |
+ Supports config extension |
+ Hardware accelerated |
+
+ Paradise |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ S3 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Hardware accelerated |
+
+ Trident TGUI 9440. Doesn't work under Windows! |
+ 100% portable |
+ Banked and linear modes |
+ No FreeBE/AF extensions |
+ Hardware accelerated |
+
+ Trident |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ Tseng ET3000/ET4000/ET6000 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ Video-7 |
+ Uses BIOS |
+ Banked modes only |
+ Supports farptr extension |
+ Dumb framebuffer |
+
+ stub driver (for testing and development purposes only) |
+ Uses BIOS |
+ Banked and linear modes |
+ Supports farptr and config extensions |
+ Slow software emulation of hardware drawing functions |
+
+
+
+
+
+ If you want to add a new driver, follow these steps:
+
+ md cardname
+ copy stub\*.* cardname
+ edit makefile
+ { add a new entry to the DRIVERS variable at the top of the file }
+ cd cardname
+ edit drvhdr.c
+ { replace "stub driver implementation" with your driver name }
+ edit driver.c
+ { fill in the blanks, replacing the VESA calls with chipset-specific }
+ { code, and fleshing out the accelerated drawing functions }
+ edit notes.txt
+ { describe anything interesting about your driver, most importantly }
+ { listing what drawing functions it supports in hardware }
+ cd..
+ done!
+
+ The makefile requires each driver to provide a drvhdr.c file, which will
+ be linked into the drvgen.exe utility and used to generate the VBE/AF
+ header. You must also provide a notes.txt, which will be displayed by the
+ installation program, but everything else is entirely up to you. Any C
+ source files placed into your driver directory will automatically be
+ compiled and linked into the driver binary, so you can organise your code
+ in whatever style you prefer.
+
+ Because the VBE/AF drivers are output as relocatable binary modules, they
+ cannot use any C library functions. There are a few utility functions in
+ helper.c, but these will not work on any platforms other than DOS+DPMI,
+ so it would be better to avoid using them if you can manage without.
+
+ A great deal of hardware information can be found in the VGADOC package
+ (ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/vgadoc4b.zip) and the
+ XFree86 sources (http://www.xfree86.org/). If this isn't enough, try
+ asking the manufacturer for more details.
+
+
+
+
+
+ freebe.txt - ASCII format documentation
+ freebe.html - HTML format documentation
+ freebe._tx - custom format documentation source file
+ makefile - script for building the drivers
+ vbeaf.h - VBE/AF structures and constants
+ start.s - driver relocation code
+ helper.c - debugging trace printf() and VESA helper routines
+ drvgen.c - modified version of DXEGEN, for building vbeaf.drv
+ drv.ld - linker script
+ install.c - installation program for binary distributions
+
+ stub/vbeaf.drv - example driver, using VESA to access the hardware
+ stub/driver.c - main implementation file for the example driver
+ stub/drvhdr.c - VBE/AF header structure for the example driver
+ stub/notes.txt - more information about the example driver
+
+ ati/ - ATI 18800/28800 driver, based on old Allegro code
+ avance/ - Avance Logic driver, by George Foot
+ cirrus54/ - Cirrus 54x driver, by Michal Mertl
+ mach64/ - ATI mach64 driver, by Ove Kaaven
+ matrox/ - Matrox driver, by Shawn Hargreaves
+ nvidia/ - NVidia driver, by Shawn Hargreaves
+ paradise/ - Paradise driver, based on old Allegro code
+ s3/ - S3 driver, by Michal Stencl
+ tgui/ - Trident TGUI 9440 driver, by Salvador Eduardo Tropea
+ trident/ - Trident driver, based on old Allegro code
+ tseng/ - Tseng driver, based on old Allegro code
+ video7/ - Video-7 driver, based on old Allegro code
+
+
+
+
+
+ As the name implies, FreeBE/AF is free. Both the driver binaries and
+ sources may be distributed and modified without restriction. If you find
+ any of this stuff useful, the best way to repay us is by writing a new
+ driver for a card that isn't currently supported.
+
+ Disclaimer: no warranty is provided with this software. We are not to be
+ held liable if it fries your monitor, eats your graphics card, or roasts
+ your motherboard.
+
+
+
+
+
+ The DRVGEN utility is based on the djgpp DXEGEN system, by Charles
+ Sandmann (sandmann@clio.rice.edu) and DJ Delorie (dj@delorie.com).
+
+ Linking/relocation system and ATI mach64 driver by Ove Kaaven
+ (ovek@arcticnet.no).
+
+ VBE/AF framework, stub driver, Matrox driver, NVidia driver, most of the
+ old Allegro chipset drivers, conversion from Allegro to VBE/AF format,
+ and installation program by Shawn Hargreaves (shawn@talula.demon.co.uk).
+
+ Cirrus 54x driver by Michal Mertl (mime@eunet.cz).
+
+ Trident TGUI 9440 driver by Salvador Eduardo Tropea (set-soft@usa.net).
+
+ Avance Logic driver by George Foot (george.foot@merton.oxford.ac.uk).
+
+ Fixes to the Cirrus 5446 MMIO routines by Keir Fraser (kaf24@cam.ac.uk).
+
+ Tseng ET6000 support by Ben Chauveau (bendomc@worldnet.fr).
+
+ Paradise driver by Francois Charton (deef@pobox.oleane.com).
+
+ Tseng ET4000 15/24 bit support by Marco Campinoti (marco@etruscan.li.it).
+
+ Trident driver improved by Mark Habersack (grendel@ananke.amu.edu.pl).
+
+ Video-7 fixes by Markus Oberhumer (markus.oberhumer@jk.uni-linz.ac.at).
+
+ S3 driver improved by Michael Bukin (M.A.Bukin@inp.nsk.su).
+
+ Video-7 driver by Peter Monks (Peter_Monks@australia.notes.pw.com).
+
+ S3 hardware acceleration by Michal Stencl (stenclpmd@ba.telecom.sk).
+
+ Website logo by Colin Walsh (cwalsh@nf.sympatico.ca).
+
+ More graphics hardware support by [insert your name here] :-)
+
+ VBE/AF itself is the brainchild of SciTech software, and in particular
+ Kendall Bennett (KendallB@scitechsoft.com).
+
+ The Video Electronics Standards Association does _not_ deserve any
+ mention here. The absurd prices they charge for copies of the /AF
+ specification have prevented it from being widely supported, and I think
+ this is a great pity. Long live freedom!
+
+
+
+
+
+ 30 March, 1998 - v0.1.
+ First public release, containing an example driver implementation that
+ runs on top of VESA.
+
+ 31 March, 1998 - v0.11.
+ Added support for multi-buffered modes.
+
+ 5 April, 1998 - v0.2.
+ Added an accelerated Matrox driver.
+
+ 8 April, 1998 - v0.3.
+ Added accelerated drivers for ATI mach64 and Cirrus 54x cards, plus
+ minor updates to the Matrox driver.
+
+ 12 April, 1998 - v0.4.
+ Proper installation program, more drawing functions implemented by the
+ stub and Matrox drivers, improved ATI driver, compiled with PGCC for a
+ 5% speed boost.
+
+ 26 April, 1998 - v0.5.
+ More accelerated features in the Cirrus and ATI drivers. Fixed bugs in
+ the Matrox driver. Added an option to disable hardware emulation in
+ the stub driver, which produces a non-accelerated, dumb framebuffer
+ implementation. The init code will now politely fail any programs that
+ try to use VBE/AF 1.0 functions, rather than just crashing.
+
+ 10 June, 1998 - v0.6.
+ Fixed scrolling problem on Millenium cards.
+
+ 1 November, 1998 - v0.7.
+ Added drivers for Trident TGUI 9440 and Avance Logic cards, and
+ improved the build process.
+
+ 14 December, 1998 - v0.8.
+ Bugfixes to the Matrox Millenium II and Cirrus drivers. Converted all
+ the old Allegro library chipset drivers into non-accelerated VBE/AF
+ format, adding support for ATI 18800/28800, Paradise, S3, Trident,
+ Tseng ET3000/ET4000/ET6000, and Video-7 boards. Designed and
+ implemented an API extension mechanism, providing the ability to use
+ these drivers in a true protected mode environment, a more rational
+ relocation scheme, and various hooks that will later be needed for
+ supporting the SciTech Nucleus drivers.
+
+ 20 December, 1998 - v0.9.
+ Bugfixes. Added a config mechanism, allowing the install program to
+ optionally disable some features of a driver.
+
+ 3 January, 1999 - v1.0
+ Bugfixes.
+
+ 27 March, 1999 - v1.1
+ Added acceleration support to the S3 driver, plus some bugfixes.
+
+ 27 June, 1999 - v1.2
+ Added driver for NVidia cards. Improved the PCI bus scanning code to
+ know about bridges to secondary devices (so it can locate AGP cards).
+ Minor bugfix to the Mach64 driver (it was using the wrong clip rect
+ for scrolling displays). Minor bugfix to the Matrox driver (it was
+ setting the wrong background color for the hardware cursor).
+
diff --git a/freebe.mft b/freebe.mft
new file mode 100644
index 0000000..5fda4ba
--- /dev/null
+++ b/freebe.mft
@@ -0,0 +1,80 @@
+freebe/
+freebe/makefile
+freebe/drvgen.c
+freebe/vbeaf.h
+freebe/start.s
+freebe/drv.ld
+freebe/zipup.btm
+freebe/freebe._tx
+freebe/helper.c
+freebe/install.c
+freebe/nvidia/
+freebe/nvidia/notes.txt
+freebe/nvidia/riva_hw.c
+freebe/nvidia/riva_hw.h
+freebe/nvidia/drvhdr.c
+freebe/nvidia/font.h
+freebe/nvidia/driver.c
+freebe/nvidia/riva_tbl.h
+freebe/freebe.html
+freebe/video7/
+freebe/video7/driver.c
+freebe/video7/drvhdr.c
+freebe/video7/notes.txt
+freebe/tseng/
+freebe/tseng/driver.c
+freebe/tseng/drvhdr.c
+freebe/tseng/notes.txt
+freebe/trident/
+freebe/trident/driver.c
+freebe/trident/drvhdr.c
+freebe/trident/notes.txt
+freebe/paradise/
+freebe/paradise/driver.c
+freebe/paradise/drvhdr.c
+freebe/paradise/notes.txt
+freebe/s3/
+freebe/s3/driver.c
+freebe/s3/drvhdr.c
+freebe/s3/notes.txt
+freebe/tgui/
+freebe/tgui/notes.txt
+freebe/tgui/driver.c
+freebe/tgui/setmode.c
+freebe/tgui/drvhdr.c
+freebe/tgui/mytypes.h
+freebe/tgui/regs.h
+freebe/tgui/rw_regs.c
+freebe/tgui/font.h
+freebe/tgui/setmode.h
+freebe/tgui/tgui.h
+freebe/tgui/vga.h
+freebe/tgui/vbeaf.htm
+freebe/tgui/html.frt
+freebe/ati/
+freebe/ati/driver.c
+freebe/ati/drvhdr.c
+freebe/ati/notes.txt
+freebe/avance/
+freebe/avance/driver.c
+freebe/avance/drvhdr.c
+freebe/avance/notes.txt
+freebe/mach64/
+freebe/mach64/notes.txt
+freebe/mach64/driver.c
+freebe/mach64/drvhdr.c
+freebe/cirrus54/
+freebe/cirrus54/drvhdr.c
+freebe/cirrus54/driver.c
+freebe/cirrus54/cirdefs.h
+freebe/cirrus54/notes.txt
+freebe/matrox/
+freebe/matrox/notes.txt
+freebe/matrox/drvhdr.c
+freebe/matrox/driver.c
+freebe/stub/
+freebe/stub/driver.c
+freebe/stub/drvhdr.c
+freebe/stub/notes.txt
+freebe/freebe.txt
+freebe/freebe.mft
diff --git a/freebe.txt b/freebe.txt
new file mode 100644
index 0000000..c3c29a4
--- /dev/null
+++ b/freebe.txt
@@ -0,0 +1,421 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ The free VBE/AF driver project, version 1.2
+
+ http://www.talula.demon.co.uk/freebe/
+
+
+ "The nice thing about standards is that
+ there are so many of them to choose from."
+
+
+
+======================================
+============ Introduction ============
+======================================
+
+ VBE/AF is a low level driver interface for accessing graphics hardware.
+ It provides all the same features as VESA 3.0 (access to linear
+ framebuffer video memory, high speed protected mode bank switching, page
+ flipping, hardware scrolling, etc), and adds the ability to use 2D
+ hardware acceleration in an efficient and portable manner. An /AF driver
+ is provided as a disk file (vbeaf.drv), and contains clean 32 bit machine
+ code which can be called directly by a C program. If implemented
+ correctly, these drivers have the potential to be binary portable across
+ multiple operating systems, so the same driver file can be used from DOS,
+ Windows, Linux, etc.
+
+ FreeBE/AF is an attempt to implement free VBE/AF drivers on as many cards
+ as possible. This idea came about on the Allegro mailing list, due to the
+ need for a dynamically loadable driver structure that could support
+ hardware acceleration. VBE/AF seemed to fit the bill, and Allegro already
+ had support for the SciTech drivers, so it seemed like a good idea to
+ adopt this format for ourselves. The primary goal is to make these
+ drivers work with Allegro, so the emphasis will be on implementing the
+ functions that Allegro actually uses, but we encourage other developers
+ to join us in taking advantage of this excellent driver architecture.
+
+ This project currently provides fully accelerated drivers for a handful
+ of chipsets, plus a number of dumb framebuffer implementations based on
+ the video drivers from older versions of the Allegro library. It has also
+ defined a few extensions to the stock VBE/AF API, which allow Allegro
+ programs to use these drivers in a true protected mode environment
+ without having to resort to the nearptr hack, and provide a number of
+ hook functions that will be needed to remain compatible with future
+ generations of the SciTech drivers.
+
+ The current status of the VBE/AF standard is somewhat confused. It was
+ designed by SciTech Software (http://www.scitechsoft.com/), who provide
+ commercial VBE/AF drivers for a wide range of cards as part of their
+ Display Doctor package. It was originally going to be released as a VESA
+ standard, but the VESA people seriously messed this up by charging
+ exorbitant sums of $$$ for copies of the spec. As a result, very few
+ people bothered to support these drivers, and the FreeBE/AF project was
+ only made possible by the information available in the SciTech MGL
+ library source code, and the helpfulness of Kendall Bennett (the designer
+ of the spec) himself. Unfortunately SciTech have now abandoned VBE/AF
+ themselves, replacing it with an equivalent but non-public API called
+ Nucleus, which is only available under NDA. SciTech will continue to
+ provide VBE/AF drivers for the cards which they already support, but
+ will not adding any new ones in the future, so this project is now the
+ only active source of VBE/AF driver implementations.
+
+ At present, the Allegro (http://www.talula.demon.co.uk/allegro/) and MGL
+ (http://www.scitechsoft.com) libraries are the only major packages which
+ can take advantage of accelerated VBE/AF drivers. As such, this project
+ is starting to look more like a implementation of video drivers
+ specifically for the Allegro library, rather than a potential
+ industry-wide standard :-) But it doesn't have to be this way! VBE/AF is
+ technically an excellent design: efficient, easy to write and use, and
+ highly portable. If you are writing graphics code, and getting frustrated
+ by the many limitiations imposed by VESA, why not think about using
+ VBE/AF instead? Even better, if you have a card that our project doesn't
+ yet support, why not add a new driver for it? This can be a lot of fun,
+ and we would be delighted to offer any help or advice that you might need.
+
+
+
+===============================
+============ Usage ============
+===============================
+
+ Each driver is located in a different subdirectory. Run "make" to compile
+ them, choose the one you want, copy the vbeaf.drv file from this
+ directory to c:\, and you are ready to go!
+
+ The stub directory contains a generic non-accelerated VBE/AF driver. This
+ is not useful in any way, because it simply sits on top of your existing
+ VESA driver and emulates a few "hardware" drawing operations with very
+ slow software implementations. The stub is intended as a starting point
+ for people who want to make drivers for a specific card, and should not
+ be used directly.
+
+ To recompile FreeBE/AF, you need a working copy of djgpp. Run "make" to
+ build all the available drivers, or "make dir/vbeaf.drv" to compile a
+ specific driver (replacing {dir} with the directory name, eg. "make
+ stub/vbeaf.drv"). To build the install.exe program for a binary
+ distribution, run "make all" (this requires you to have the Allegro
+ library installed, and the allegro/tools/ directory in your path). This
+ documentation is converted from the custom ._tx format into ASCII and
+ HTML by the Allegro makedoc program: run "make docs" to do this, after
+ putting the makedoc utility somewhere in your path.
+
+ FreeBE/AF only supports the VBE/AF 2.0 API. It is not backward compatible
+ with the assembler VBE/AF 1.0 interface, and programs that try to use
+ those obsolete functions will not work correctly.
+
+
+
+============================================
+============ Supported Hardware ============
+============================================
+
+ Not all VBE/AF drivers provide the complete set of possible features.
+ Some may be written in a 100% clean and portable manner, allowing them to
+ be used on any platform, but others make use of the video BIOS in order
+ to set the initial video mode: this makes them a lot easier to write, but
+ means that it can only be used under DOS. Some of the drivers, in
+ particular the ones based on the old Allegro library chipset support,
+ don't support any hardware accelerated drawing at all: these are still
+ usefull because they provide high speed protected mode bank switching and
+ can work around the bugs in some manufacturer's VESA implementations, but
+ are obviously not nearly as cool as a fully accelerated driver.
+
+ This table lists the currently available FreeBE/AF drivers, and what
+ features they each provide:
+
+ ATI 18800/28800
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Dumb framebuffer
+
+ ATI mach64
+ Uses BIOS
+ Banked and linear modes
+ No FreeBE/AF extensions
+ Hardware accelerated
+
+ Avance Logic ALG-2101, ALG-2201, ALG-2228, ALG-2301, ALG-2302
+ Uses BIOS
+ Banked modes only
+ No FreeBE/AF extensions
+ Dumb framebuffer
+
+ Cirrus 54xx (not 546x). Should be ok with 5426, 5428, 7541, 7543
+ Uses BIOS
+ Banked and linear modes
+ No FreeBE/AF extensions
+ Hardware accelerated
+
+ Matrox Millenium, Mystique, Millenium II
+ Uses BIOS
+ Banked and linear modes
+ Supports farptr and config extensions
+ Hardware accelerated
+
+ NVidia Riva 128, TNT. Conflicts with Windows!
+ 100% portable
+ Banked and linear modes
+ Supports config extension
+ Hardware accelerated
+
+ Paradise
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Dumb framebuffer
+
+ S3
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Hardware accelerated
+
+ Trident TGUI 9440. Doesn't work under Windows!
+ 100% portable
+ Banked and linear modes
+ No FreeBE/AF extensions
+ Hardware accelerated
+
+ Trident
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Dumb framebuffer
+
+ Tseng ET3000/ET4000/ET6000
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Dumb framebuffer
+
+ Video-7
+ Uses BIOS
+ Banked modes only
+ Supports farptr extension
+ Dumb framebuffer
+
+ stub driver (for testing and development purposes only)
+ Uses BIOS
+ Banked and linear modes
+ Supports farptr and config extensions
+ Slow software emulation of hardware drawing functions
+
+
+
+======================================
+============ Contributing ============
+======================================
+
+ If you want to add a new driver, follow these steps:
+
+ md cardname
+ copy stub\*.* cardname
+ edit makefile
+ { add a new entry to the DRIVERS variable at the top of the file }
+ cd cardname
+ edit drvhdr.c
+ { replace "stub driver implementation" with your driver name }
+ edit driver.c
+ { fill in the blanks, replacing the VESA calls with chipset-specific }
+ { code, and fleshing out the accelerated drawing functions }
+ edit notes.txt
+ { describe anything interesting about your driver, most importantly }
+ { listing what drawing functions it supports in hardware }
+ cd..
+ done!
+
+ The makefile requires each driver to provide a drvhdr.c file, which will
+ be linked into the drvgen.exe utility and used to generate the VBE/AF
+ header. You must also provide a notes.txt, which will be displayed by the
+ installation program, but everything else is entirely up to you. Any C
+ source files placed into your driver directory will automatically be
+ compiled and linked into the driver binary, so you can organise your code
+ in whatever style you prefer.
+
+ Because the VBE/AF drivers are output as relocatable binary modules, they
+ cannot use any C library functions. There are a few utility functions in
+ helper.c, but these will not work on any platforms other than DOS+DPMI,
+ so it would be better to avoid using them if you can manage without.
+
+ A great deal of hardware information can be found in the VGADOC package
+ (ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/vgadoc4b.zip) and the
+ XFree86 sources (http://www.xfree86.org/). If this isn't enough, try
+ asking the manufacturer for more details.
+
+
+
+===============================
+============ Files ============
+===============================
+
+ freebe.txt - ASCII format documentation
+ freebe.html - HTML format documentation
+ freebe._tx - custom format documentation source file
+ makefile - script for building the drivers
+ vbeaf.h - VBE/AF structures and constants
+ start.s - driver relocation code
+ helper.c - debugging trace printf() and VESA helper routines
+ drvgen.c - modified version of DXEGEN, for building vbeaf.drv
+ drv.ld - linker script
+ install.c - installation program for binary distributions
+
+ stub/vbeaf.drv - example driver, using VESA to access the hardware
+ stub/driver.c - main implementation file for the example driver
+ stub/drvhdr.c - VBE/AF header structure for the example driver
+ stub/notes.txt - more information about the example driver
+
+ ati/ - ATI 18800/28800 driver, based on old Allegro code
+ avance/ - Avance Logic driver, by George Foot
+ cirrus54/ - Cirrus 54x driver, by Michal Mertl
+ mach64/ - ATI mach64 driver, by Ove Kaaven
+ matrox/ - Matrox driver, by Shawn Hargreaves
+ nvidia/ - NVidia driver, by Shawn Hargreaves
+ paradise/ - Paradise driver, based on old Allegro code
+ s3/ - S3 driver, by Michal Stencl
+ tgui/ - Trident TGUI 9440 driver, by Salvador Eduardo Tropea
+ trident/ - Trident driver, based on old Allegro code
+ tseng/ - Tseng driver, based on old Allegro code
+ video7/ - Video-7 driver, based on old Allegro code
+
+
+
+===================================
+============ Copyright ============
+===================================
+
+ As the name implies, FreeBE/AF is free. Both the driver binaries and
+ sources may be distributed and modified without restriction. If you find
+ any of this stuff useful, the best way to repay us is by writing a new
+ driver for a card that isn't currently supported.
+
+ Disclaimer: no warranty is provided with this software. We are not to be
+ held liable if it fries your monitor, eats your graphics card, or roasts
+ your motherboard.
+
+
+
+=================================
+============ Credits ============
+=================================
+
+ The DRVGEN utility is based on the djgpp DXEGEN system, by Charles
+ Sandmann (sandmann@clio.rice.edu) and DJ Delorie (dj@delorie.com).
+
+ Linking/relocation system and ATI mach64 driver by Ove Kaaven
+ (ovek@arcticnet.no).
+
+ VBE/AF framework, stub driver, Matrox driver, NVidia driver, most of the
+ old Allegro chipset drivers, conversion from Allegro to VBE/AF format,
+ and installation program by Shawn Hargreaves (shawn@talula.demon.co.uk).
+
+ Cirrus 54x driver by Michal Mertl (mime@eunet.cz).
+
+ Trident TGUI 9440 driver by Salvador Eduardo Tropea (set-soft@usa.net).
+
+ Avance Logic driver by George Foot (george.foot@merton.oxford.ac.uk).
+
+ Fixes to the Cirrus 5446 MMIO routines by Keir Fraser (kaf24@cam.ac.uk).
+
+ Tseng ET6000 support by Ben Chauveau (bendomc@worldnet.fr).
+
+ Paradise driver by Francois Charton (deef@pobox.oleane.com).
+
+ Tseng ET4000 15/24 bit support by Marco Campinoti (marco@etruscan.li.it).
+
+ Trident driver improved by Mark Habersack (grendel@ananke.amu.edu.pl).
+
+ Video-7 fixes by Markus Oberhumer (markus.oberhumer@jk.uni-linz.ac.at).
+
+ S3 driver improved by Michael Bukin (M.A.Bukin@inp.nsk.su).
+
+ Video-7 driver by Peter Monks (Peter_Monks@australia.notes.pw.com).
+
+ S3 hardware acceleration by Michal Stencl (stenclpmd@ba.telecom.sk).
+
+ Website logo by Colin Walsh (cwalsh@nf.sympatico.ca).
+
+ More graphics hardware support by [insert your name here] :-)
+
+ VBE/AF itself is the brainchild of SciTech software, and in particular
+ Kendall Bennett (KendallB@scitechsoft.com).
+
+ The Video Electronics Standards Association does _not_ deserve any
+ mention here. The absurd prices they charge for copies of the /AF
+ specification have prevented it from being widely supported, and I think
+ this is a great pity. Long live freedom!
+
+
+
+=================================
+============ History ============
+=================================
+
+ 30 March, 1998 - v0.1.
+ First public release, containing an example driver implementation that
+ runs on top of VESA.
+
+ 31 March, 1998 - v0.11.
+ Added support for multi-buffered modes.
+
+ 5 April, 1998 - v0.2.
+ Added an accelerated Matrox driver.
+
+ 8 April, 1998 - v0.3.
+ Added accelerated drivers for ATI mach64 and Cirrus 54x cards, plus
+ minor updates to the Matrox driver.
+
+ 12 April, 1998 - v0.4.
+ Proper installation program, more drawing functions implemented by the
+ stub and Matrox drivers, improved ATI driver, compiled with PGCC for a
+ 5% speed boost.
+
+ 26 April, 1998 - v0.5.
+ More accelerated features in the Cirrus and ATI drivers. Fixed bugs in
+ the Matrox driver. Added an option to disable hardware emulation in
+ the stub driver, which produces a non-accelerated, dumb framebuffer
+ implementation. The init code will now politely fail any programs that
+ try to use VBE/AF 1.0 functions, rather than just crashing.
+
+ 10 June, 1998 - v0.6.
+ Fixed scrolling problem on Millenium cards.
+
+ 1 November, 1998 - v0.7.
+ Added drivers for Trident TGUI 9440 and Avance Logic cards, and
+ improved the build process.
+
+ 14 December, 1998 - v0.8.
+ Bugfixes to the Matrox Millenium II and Cirrus drivers. Converted all
+ the old Allegro library chipset drivers into non-accelerated VBE/AF
+ format, adding support for ATI 18800/28800, Paradise, S3, Trident,
+ Tseng ET3000/ET4000/ET6000, and Video-7 boards. Designed and
+ implemented an API extension mechanism, providing the ability to use
+ these drivers in a true protected mode environment, a more rational
+ relocation scheme, and various hooks that will later be needed for
+ supporting the SciTech Nucleus drivers.
+
+ 20 December, 1998 - v0.9.
+ Bugfixes. Added a config mechanism, allowing the install program to
+ optionally disable some features of a driver.
+
+ 3 January, 1999 - v1.0
+ Bugfixes.
+
+ 27 March, 1999 - v1.1
+ Added acceleration support to the S3 driver, plus some bugfixes.
+
+ 27 June, 1999 - v1.2
+ Added driver for NVidia cards. Improved the PCI bus scanning code to
+ know about bridges to secondary devices (so it can locate AGP cards).
+ Minor bugfix to the Mach64 driver (it was using the wrong clip rect
+ for scrolling displays). Minor bugfix to the Matrox driver (it was
+ setting the wrong background color for the hardware cursor).
+
diff --git a/helper.c b/helper.c
new file mode 100644
index 0000000..0056fd1
--- /dev/null
+++ b/helper.c
@@ -0,0 +1,649 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Assorted helper routines for use by the /AF drivers.
+ *
+ * The code in this file makes heavy use of DPMI and VESA functions,
+ * so any drivers that use these helpers will not be portable to
+ * Linux. For maximum portability, a driver should use direct hardware
+ * access for all features, and not touch any of these routines.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include
+#include
+
+#include "vbeaf.h"
+
+
+
+/* trace_putc:
+ * Debugging trace function
+ */
+void trace_putc(char c)
+{
+ asm (
+ " int $0x21 "
+
+ :
+
+ : "a" (0x200),
+ "d" (c)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+}
+
+
+
+/* trace_printf:
+ * Debugging trace function: supports %c, %s, %d, and %x
+ */
+void trace_printf(char *msg, ...)
+{
+ static char hex_digit[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ unsigned long l;
+ char *s;
+ int c, i;
+
+ va_list ap;
+ va_start(ap, msg);
+
+ while (*msg) {
+ if (*msg == '%') {
+ /* handle escape token */
+ msg++;
+
+ switch (*msg) {
+
+ case '%':
+ trace_putc('%');
+ break;
+
+ case 'c':
+ c = va_arg(ap, char);
+ trace_putc(c);
+ break;
+
+ case 's':
+ s = va_arg(ap, char *);
+ while (*s) {
+ if (*s == '\n')
+ trace_putc('\r');
+ trace_putc(*s);
+ s++;
+ }
+ break;
+
+ case 'd':
+ c = va_arg(ap, int);
+ if (c < 0) {
+ trace_putc('-');
+ c = -c;
+ }
+ i = 1;
+ while (i*10 <= c)
+ i *= 10;
+ while (i) {
+ trace_putc('0'+c/i);
+ c %= i;
+ i /= 10;
+ }
+ break;
+
+ case 'x':
+ l = va_arg(ap, unsigned long);
+ for (i=7; i>=0; i--)
+ trace_putc(hex_digit[(l>>(i*4))&0xF]);
+ break;
+ }
+
+ if (*msg)
+ msg++;
+ }
+ else {
+ /* output normal character */
+ if (*msg == '\n')
+ trace_putc('\r');
+ trace_putc(*msg);
+ msg++;
+ }
+ }
+
+ va_end(ap);
+}
+
+
+
+/* rm_int:
+ * Calls a real mode interrupt: basically the same thing as __dpmi_int().
+ */
+void rm_int(int num, RM_REGS *regs)
+{
+ regs->x.flags = 0;
+ regs->x.sp = 0;
+ regs->x.ss = 0;
+
+ asm (
+ " int $0x31 "
+ :
+
+ : "a" (0x300),
+ "b" (num),
+ "c" (0),
+ "D" (regs)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+}
+
+
+
+/* allocate_dos_memory:
+ * Allocates a block of conventional memory, returning a real mode segment
+ * address, and filling in the protected mode selector for accessing it.
+ * Returns -1 on error.
+ */
+int allocate_dos_memory(int size, int *sel)
+{
+ int rm_seg;
+ int pm_sel;
+ int ok;
+
+ asm (
+ " int $0x31 ; "
+ " jc 0f ; "
+ " movl $1, %2 ; "
+ " jmp 1f ; "
+ " 0: "
+ " movl $0, %2 ; "
+ " 1: "
+
+ : "=a" (rm_seg),
+ "=d" (pm_sel),
+ "=m" (ok)
+
+ : "a" (0x100),
+ "b" ((size+15)/16)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+
+ if (!ok)
+ return -1;
+
+ *sel = pm_sel;
+ return rm_seg;
+}
+
+
+
+/* free_dos_memory:
+ * Frees a block of conventional memory, given a selector previously
+ * returned by a call allocate_dos_memory().
+ */
+void free_dos_memory(int sel)
+{
+ asm (
+ " int $0x31 "
+ :
+
+ : "a" (0x101),
+ "d" (sel)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+}
+
+
+
+/* allocate_selector:
+ * Creates a selector for accessing the specified linear memory region,
+ * returning a selector value or -1 on error.
+ */
+int allocate_selector(int addr, int size)
+{
+ int sel;
+ int ok;
+
+ asm (
+ " int $0x31 ; "
+ " jc 0f ; "
+
+ " movl %%eax, %%ebx ; "
+ " movl $7, %%eax ; "
+ " movl %4, %%ecx ; "
+ " movl %5, %%edx ; "
+ " int $0x31 ; "
+ " jc 0f ; "
+
+ " movl $8, %%eax ; "
+ " movl %6, %%ecx ; "
+ " movl %7, %%edx ; "
+ " int $0x31 ; "
+ " jc 0f ; "
+
+ " movl $1, %1 ; "
+ " jmp 1f ; "
+
+ " 0: "
+ " movl $1, %1 ; "
+ " 1: "
+
+ : "=b" (sel),
+ "=D" (ok)
+
+ : "a" (0),
+ "c" (1),
+ "m" (addr>>16),
+ "m" (addr&0xFFFF),
+ "m" ((size-1)>>16),
+ "m" ((size-1)&0xFFFF)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+
+ if (!ok)
+ return -1;
+
+ return sel;
+}
+
+
+
+/* free_selector:
+ * Destroys a selector that was previously created with the
+ * allocate_selector() function.
+ */
+void free_selector(int sel)
+{
+ asm (
+ " int $0x31 "
+ :
+
+ : "a" (1),
+ "b" (sel)
+
+ : "%eax",
+ "%ebx",
+ "%ecx",
+ "%edx",
+ "%esi",
+ "%edi"
+ );
+}
+
+
+
+/* Helper routines for accessing the underlying VESA interface.
+ */
+
+
+#define MASK_LINEAR(addr) (addr & 0x000FFFFF)
+#define RM_TO_LINEAR(addr) (((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF))
+#define RM_OFFSET(addr) (addr & 0xF)
+#define RM_SEGMENT(addr) ((addr >> 4) & 0xFFFF)
+
+
+
+typedef struct VESA_INFO /* VESA information block structure */
+{
+ unsigned char VESASignature[4] __attribute__ ((packed));
+ unsigned short VESAVersion __attribute__ ((packed));
+ unsigned long OEMStringPtr __attribute__ ((packed));
+ unsigned char Capabilities[4] __attribute__ ((packed));
+ unsigned long VideoModePtr __attribute__ ((packed));
+ unsigned short TotalMemory __attribute__ ((packed));
+ unsigned short OemSoftwareRev __attribute__ ((packed));
+ unsigned long OemVendorNamePtr __attribute__ ((packed));
+ unsigned long OemProductNamePtr __attribute__ ((packed));
+ unsigned long OemProductRevPtr __attribute__ ((packed));
+ unsigned char Reserved[222] __attribute__ ((packed));
+ unsigned char OemData[256] __attribute__ ((packed));
+} VESA_INFO;
+
+
+
+typedef struct VESA_MODE_INFO /* VESA information for a specific mode */
+{
+ unsigned short ModeAttributes __attribute__ ((packed));
+ unsigned char WinAAttributes __attribute__ ((packed));
+ unsigned char WinBAttributes __attribute__ ((packed));
+ unsigned short WinGranularity __attribute__ ((packed));
+ unsigned short WinSize __attribute__ ((packed));
+ unsigned short WinASegment __attribute__ ((packed));
+ unsigned short WinBSegment __attribute__ ((packed));
+ unsigned long WinFuncPtr __attribute__ ((packed));
+ unsigned short BytesPerScanLine __attribute__ ((packed));
+ unsigned short XResolution __attribute__ ((packed));
+ unsigned short YResolution __attribute__ ((packed));
+ unsigned char XCharSize __attribute__ ((packed));
+ unsigned char YCharSize __attribute__ ((packed));
+ unsigned char NumberOfPlanes __attribute__ ((packed));
+ unsigned char BitsPerPixel __attribute__ ((packed));
+ unsigned char NumberOfBanks __attribute__ ((packed));
+ unsigned char MemoryModel __attribute__ ((packed));
+ unsigned char BankSize __attribute__ ((packed));
+ unsigned char NumberOfImagePages __attribute__ ((packed));
+ unsigned char Reserved_page __attribute__ ((packed));
+ unsigned char RedMaskSize __attribute__ ((packed));
+ unsigned char RedMaskPos __attribute__ ((packed));
+ unsigned char GreenMaskSize __attribute__ ((packed));
+ unsigned char GreenMaskPos __attribute__ ((packed));
+ unsigned char BlueMaskSize __attribute__ ((packed));
+ unsigned char BlueMaskPos __attribute__ ((packed));
+ unsigned char ReservedMaskSize __attribute__ ((packed));
+ unsigned char ReservedMaskPos __attribute__ ((packed));
+ unsigned char DirectColorModeInfo __attribute__ ((packed));
+
+ /* VBE 2.0 extensions */
+ unsigned long PhysBasePtr __attribute__ ((packed));
+ unsigned long OffScreenMemOffset __attribute__ ((packed));
+ unsigned short OffScreenMemSize __attribute__ ((packed));
+
+ /* VBE 3.0 extensions */
+ unsigned short LinBytesPerScanLine __attribute__ ((packed));
+ unsigned char BnkNumberOfPages __attribute__ ((packed));
+ unsigned char LinNumberOfPages __attribute__ ((packed));
+ unsigned char LinRedMaskSize __attribute__ ((packed));
+ unsigned char LinRedFieldPos __attribute__ ((packed));
+ unsigned char LinGreenMaskSize __attribute__ ((packed));
+ unsigned char LinGreenFieldPos __attribute__ ((packed));
+ unsigned char LinBlueMaskSize __attribute__ ((packed));
+ unsigned char LinBlueFieldPos __attribute__ ((packed));
+ unsigned char LinRsvdMaskSize __attribute__ ((packed));
+ unsigned char LinRsvdFieldPos __attribute__ ((packed));
+ unsigned long MaxPixelClock __attribute__ ((packed));
+
+ unsigned char Reserved[190] __attribute__ ((packed));
+} VESA_MODE_INFO;
+
+
+
+#define MAX_VESA_MODES 256
+
+
+
+#define SAFETY_BUFFER 4096
+
+
+
+/* get_vesa_info:
+ * Retrieves data from the VESA info block structure and mode list,
+ * returning 0 for success.
+ */
+int get_vesa_info(int *vram_size, unsigned long *linear_addr, void (*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))
+{
+ VESA_INFO vesa_info;
+ VESA_MODE_INFO mode_info;
+ RM_REGS r;
+ int mode_list[MAX_VESA_MODES];
+ long mode_ptr;
+ int num_modes;
+ int seg, sel;
+ int c, i;
+
+ /* fetch the VESA info block */
+ seg = allocate_dos_memory(sizeof(VESA_INFO)+SAFETY_BUFFER, &sel);
+ if (seg < 0)
+ return -1;
+
+ for (c=0; c<(int)sizeof(VESA_INFO); c++)
+ _farpokeb(sel, c, 0);
+
+ _farpokeb(sel, 0, 'V');
+ _farpokeb(sel, 1, 'B');
+ _farpokeb(sel, 2, 'E');
+ _farpokeb(sel, 3, '2');
+
+ r.x.ax = 0x4F00;
+ r.x.di = 0;
+ r.x.es = seg;
+ rm_int(0x10, &r);
+ if (r.h.ah) {
+ free_dos_memory(sel);
+ return -1;
+ }
+
+ for (c=0; c<(int)sizeof(VESA_INFO); c++)
+ ((char *)&vesa_info)[c] = _farpeekb(sel, c);
+
+ free_dos_memory(sel);
+
+ if ((vesa_info.VESASignature[0] != 'V') ||
+ (vesa_info.VESASignature[1] != 'E') ||
+ (vesa_info.VESASignature[2] != 'S') ||
+ (vesa_info.VESASignature[3] != 'A'))
+ return -1;
+
+ *vram_size = vesa_info.TotalMemory << 16;
+
+ if (linear_addr)
+ *linear_addr = 0;
+
+ sel = allocate_selector(0, 1024*1024);
+ if (sel < 0)
+ return -1;
+
+ /* read the mode list */
+ mode_ptr = RM_TO_LINEAR(vesa_info.VideoModePtr);
+ num_modes = 0;
+
+ while ((mode_list[num_modes] = _farpeekw(sel, mode_ptr)) != 0xFFFF) {
+ num_modes++;
+ mode_ptr += 2;
+ if (num_modes >= MAX_VESA_MODES)
+ break;
+ }
+
+ free_selector(sel);
+
+ seg = allocate_dos_memory(sizeof(VESA_MODE_INFO)+SAFETY_BUFFER, &sel);
+ if (seg < 0)
+ return -1;
+
+ /* fetch info about each supported mode */
+ for (c=0; c= 0x300) {
+ if (callback) {
+ callback(mode_list[c], TRUE,
+ mode_info.XResolution, mode_info.YResolution,
+ mode_info.BitsPerPixel, mode_info.LinBytesPerScanLine,
+ mode_info.LinRedMaskSize, mode_info.LinRedFieldPos,
+ mode_info.LinGreenMaskSize, mode_info.LinGreenFieldPos,
+ mode_info.LinBlueMaskSize, mode_info.LinBlueFieldPos,
+ mode_info.LinRsvdMaskSize, mode_info.LinRsvdFieldPos);
+ }
+ }
+ else {
+ if (callback) {
+ callback(mode_list[c], TRUE,
+ mode_info.XResolution, mode_info.YResolution,
+ mode_info.BitsPerPixel, mode_info.BytesPerScanLine,
+ mode_info.RedMaskSize, mode_info.RedMaskPos,
+ mode_info.GreenMaskSize, mode_info.GreenMaskPos,
+ mode_info.BlueMaskSize, mode_info.BlueMaskPos,
+ mode_info.ReservedMaskSize, mode_info.ReservedMaskPos);
+ }
+ }
+ }
+ else {
+ /* banked mode */
+ if (callback) {
+ callback(mode_list[c], FALSE,
+ mode_info.XResolution, mode_info.YResolution,
+ mode_info.BitsPerPixel, mode_info.BytesPerScanLine,
+ mode_info.RedMaskSize, mode_info.RedMaskPos,
+ mode_info.GreenMaskSize, mode_info.GreenMaskPos,
+ mode_info.BlueMaskSize, mode_info.BlueMaskPos,
+ mode_info.ReservedMaskSize, mode_info.ReservedMaskPos);
+ }
+ }
+ }
+ }
+ }
+
+ free_dos_memory(sel);
+
+ return 0;
+}
+
+
+
+/* FindPCIDevice:
+ * Replacement for the INT 1A - PCI BIOS v2.0c+ - FIND PCI DEVICE, AX = B102h
+ *
+ * Note: deviceIndex is because a card can hold more than one PCI chip.
+ *
+ * Searches the board of the vendor supplied in vendorID with
+ * identification number deviceID and index deviceIndex (normally 0).
+ * The value returned in handle can be used to access the PCI registers
+ * of this board.
+ *
+ * Return: 1 if found 0 if not found.
+ */
+int FindPCIDevice(int deviceID, int vendorID, int deviceIndex, int *handle)
+{
+ int model, vendor, card, device;
+ unsigned value, full_id, bus, busMax;
+
+ deviceIndex <<= 8;
+
+ /* for each PCI bus */
+ for (bus=0, busMax=0x10000; bus> 16;
+
+ if (vendor != 0xFFFF) {
+ /* is this the one we want? */
+ if ((deviceID == model) && (vendorID == vendor)) {
+ *handle = value;
+ return 1;
+ }
+
+ /* is it a bridge to a secondary bus? */
+ outportl(PCIConfigurationAddress, value | 8);
+
+ if (((inportl(PCIConfigurationData) >> 16) == 0x0600) || (full_id==0x00011011))
+ busMax += 0x10000;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* fixup_feature_list:
+ * Helper for the FAF_CFG_FEATURES extension, for blanking out any
+ * accelerated drawing routines that the install program has disabled.
+ */
+void fixup_feature_list(AF_DRIVER *af, unsigned long flags)
+{
+ if (!(flags & fafHWCursor)) {
+ af->Attributes &= ~afHaveHWCursor;
+
+ af->SetCursor = NULL;
+ af->SetCursorPos = NULL;
+ af->SetCursorColor = NULL;
+ af->ShowCursor = NULL;
+ }
+
+ if (!(flags & fafDrawScan)) af->DrawScan = NULL;
+ if (!(flags & fafDrawPattScan)) af->DrawPattScan = NULL;
+ if (!(flags & fafDrawColorPattScan)) af->DrawColorPattScan = NULL;
+ if (!(flags & fafDrawScanList)) af->DrawScanList = NULL;
+ if (!(flags & fafDrawPattScanList)) af->DrawPattScanList = NULL;
+ if (!(flags & fafDrawColorPattScanList)) af->DrawColorPattScanList = NULL;
+ if (!(flags & fafDrawRect)) af->DrawRect = NULL;
+ if (!(flags & fafDrawPattRect)) af->DrawPattRect = NULL;
+ if (!(flags & fafDrawColorPattRect)) af->DrawColorPattRect = NULL;
+ if (!(flags & fafDrawLine)) af->DrawLine = NULL;
+ if (!(flags & fafDrawStippleLine)) af->DrawStippleLine = NULL;
+ if (!(flags & fafDrawTrap)) af->DrawTrap = NULL;
+ if (!(flags & fafDrawTri)) af->DrawTri = NULL;
+ if (!(flags & fafDrawQuad)) af->DrawQuad = NULL;
+ if (!(flags & fafPutMonoImage)) af->PutMonoImage = NULL;
+ if (!(flags & fafPutMonoImageLin)) af->PutMonoImageLin = NULL;
+ if (!(flags & fafPutMonoImageBM)) af->PutMonoImageBM = NULL;
+ if (!(flags & fafBitBlt)) af->BitBlt = NULL;
+ if (!(flags & fafBitBltSys)) af->BitBltSys = NULL;
+ if (!(flags & fafBitBltLin)) af->BitBltLin = NULL;
+ if (!(flags & fafBitBltBM)) af->BitBltBM = NULL;
+ if (!(flags & fafSrcTransBlt)) af->SrcTransBlt = NULL;
+ if (!(flags & fafSrcTransBltSys)) af->SrcTransBltSys = NULL;
+ if (!(flags & fafSrcTransBltLin)) af->SrcTransBltLin = NULL;
+ if (!(flags & fafSrcTransBltBM)) af->SrcTransBltBM = NULL;
+}
+
+
diff --git a/install.c b/install.c
new file mode 100644
index 0000000..1f0ff9f
--- /dev/null
+++ b/install.c
@@ -0,0 +1,1396 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Installation utility.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "vbeaf.h"
+
+
+
+#define VBEAF_FILENAME "c:\\vbeaf.drv"
+
+
+#define ever ;;
+
+
+
+/* info about one of the VBE/AF drivers */
+typedef struct DRIVER_INFO
+{
+ char name[80];
+ AF_DRIVER *driver;
+ int driver_size;
+ char *notes;
+ int notes_size;
+ int present;
+ int accel;
+ int config;
+} DRIVER_INFO;
+
+
+
+#define MAX_DRIVERS 256
+
+
+DRIVER_INFO driver_info[MAX_DRIVERS];
+
+int num_drivers = 0;
+
+
+char current_driver_name[80];
+char current_driver_copyright[80];
+
+
+
+/* graphics characters */
+#define TL_CHAR 0xDA
+#define TOP_CHAR 0xC4
+#define TR_CHAR 0xBF
+#define SIDE_CHAR 0xB3
+#define BL_CHAR 0xC0
+#define BR_CHAR 0xD9
+#define SHADOW_CHAR 0xDB
+
+
+
+/* drawing state variables */
+int _text_color = 0;
+int _text_x = 0;
+int _text_y = 0;
+
+int screen_h;
+
+
+
+/* mouse driver state variables */
+int m_state;
+int m_x = 0;
+int m_y = 0;
+int m_b = 0;
+
+
+
+/* sets up the mouse driver */
+void mouse_init()
+{
+ __dpmi_regs reg;
+
+ reg.x.ax = 0;
+ __dpmi_int(0x33, ®);
+ m_state = reg.x.ax;
+
+ if (m_state) {
+ reg.x.ax = 10;
+ reg.x.bx = 0;
+ reg.x.cx = 0xffff;
+ reg.x.dx = 0x7700;
+ __dpmi_int(0x33, ®);
+ }
+}
+
+
+
+/* displays the mouse pointer */
+void mouse_on()
+{
+ __dpmi_regs reg;
+
+ if (m_state) {
+ reg.x.ax = 1;
+ __dpmi_int(0x33, ®);
+ }
+}
+
+
+
+/* hides the mouse pointer */
+void mouse_off()
+{
+ __dpmi_regs reg;
+
+ if (m_state) {
+ reg.x.ax = 2;
+ __dpmi_int(0x33, ®);
+ }
+}
+
+
+
+/* reads the mouse state */
+void mouse_read()
+{
+ __dpmi_regs reg;
+
+ if (m_state) {
+ reg.x.ax = 3;
+ __dpmi_int(0x33, ®);
+
+ m_x = reg.x.cx / 8;
+ m_y = reg.x.dx / 8;
+ m_b = reg.x.bx;
+ }
+}
+
+
+
+/* sets the mouse position */
+void mouse_move(int x, int y)
+{
+ __dpmi_regs reg;
+
+ if (m_state) {
+ reg.x.ax = 4;
+ reg.x.cx = x*8;
+ reg.x.dx = y*8;
+ __dpmi_int(0x33, ®);
+
+ m_x = x;
+ m_y = y;
+ }
+}
+
+
+
+/* waits for a keypress or mouse button click */
+void input_pause()
+{
+ mouse_on();
+
+ while (m_b)
+ mouse_read();
+
+ for(ever) {
+ if (keypressed()) {
+ readkey();
+ break;
+ }
+
+ mouse_read();
+ if (m_b)
+ break;
+ }
+
+ mouse_off();
+}
+
+
+
+/* sets the drawing color */
+void text_color(int c)
+{
+ _text_color = c;
+}
+
+
+
+/* sets the drawing position */
+void text_pos(int x, int y)
+{
+ _text_x = x-1;
+ _text_y = y-1;
+}
+
+
+
+/* prints a character */
+void text_c(int c)
+{
+ if (_text_x < 80)
+ _farpokew(_dos_ds, 0xB8000+_text_x*2+_text_y*160, c|(_text_color<<8));
+
+ _text_x++;
+}
+
+
+
+/* prints a string */
+void text_str(char *s)
+{
+ while (*s) {
+ text_c((unsigned char)*s);
+ s++;
+ }
+}
+
+
+
+/* prints the first part of a string */
+void text_clamp(char *s, int max)
+{
+ int i;
+
+ if ((int)strlen(s) <= max) {
+ text_str(s);
+ }
+ else {
+ for (i=0; i num) {
+ y++;
+ num -= 2;
+ }
+
+ if (samescroll)
+ scroll = oldscroll;
+ else
+ scroll = MID(0, sel-num/2, count-num);
+
+ len += 8;
+ x = 40-len/2;
+
+ sstart = clock();
+
+ for(ever) {
+ /* draw the menu */
+ for (i=0; i num) {
+ text_color(0x78);
+
+ text_pos(x+4, y);
+ if (scroll > 0)
+ text_str("--- more ---");
+ else
+ text_str(" ");
+
+ text_pos(x+4, y+num+1);
+ if (scroll < count-num)
+ text_str("--- more ---");
+ else
+ text_str(" ");
+ }
+
+ mouse_on();
+
+ while ((m_b) && (!ob))
+ mouse_read();
+
+ redraw = FALSE;
+
+ while (!redraw) {
+ if (keypressed()) {
+ /* deal with keyboard input */
+ c = readkey();
+
+ switch (c>>8) {
+
+ case KEY_UP:
+ if (sel > 0) {
+ sel--;
+ if (sel < scroll)
+ scroll = sel;
+ redraw = TRUE;
+ }
+ break;
+
+ case KEY_DOWN:
+ if (sel < count-1) {
+ sel++;
+ if (sel >= scroll+num)
+ scroll = sel-num+1;
+ redraw = TRUE;
+ }
+ break;
+
+ case KEY_PGUP:
+ if (sel > scroll) {
+ sel = scroll;
+ }
+ else {
+ sel = scroll = MAX(sel-num+1, 0);
+ }
+ redraw = TRUE;
+ break;
+
+ case KEY_PGDN:
+ if (sel < scroll+num-1) {
+ sel = scroll+num-1;
+ }
+ else {
+ sel = MIN(sel+num-1, count-1);
+ scroll = sel-num+1;
+ }
+ redraw = TRUE;
+ break;
+
+ case KEY_HOME:
+ sel = scroll = 0;
+ redraw = TRUE;
+ break;
+
+ case KEY_END:
+ sel = count-1;
+ scroll = count-num;
+ redraw = TRUE;
+ break;
+
+ case KEY_ENTER:
+ case KEY_SPACE:
+ mouse_off();
+ oldscroll = scroll;
+ return sel;
+
+ case KEY_ESC:
+ mouse_off();
+ oldscroll = scroll;
+ return -1;
+ }
+ }
+ else {
+ /* deal with mouse input */
+ mouse_read();
+
+ if (m_b & 2) {
+ /* right button cancels */
+ mouse_off();
+ oldscroll = scroll;
+ return -1;
+ }
+
+ if (m_b & 1) {
+ if ((m_x >= x-1) && (m_x < x+len-1) &&
+ (m_y >= y) && (m_y < y+num)) {
+ if (sel == m_y-y+scroll) {
+ /* double click detection */
+ start = clock();
+
+ ox = m_x;
+ oy = m_y;
+
+ /* check for release */
+ while (((clock() - start) < CLOCKS_PER_SEC/4) &&
+ (ox == m_x) && (oy == m_y) && (m_b & 1))
+ mouse_read();
+
+ if (!(m_b & 1)) {
+ start = clock();
+ ox = m_x;
+ oy = m_y;
+
+ /* check for second click */
+ while (((clock() - start) < CLOCKS_PER_SEC/4) &&
+ (ox == m_x) && (oy == m_y) && (!(m_b & 1)))
+ mouse_read();
+
+ if (m_b & 1) {
+ /* yeah! dclick... */
+ mouse_off();
+ oldscroll = scroll;
+ return sel;
+ }
+ }
+ }
+ else {
+ /* left button selects */
+ sel = m_y-y+scroll;
+ redraw = TRUE;
+ }
+ }
+ else if ((m_x >= x-1) && (m_x < x+len-1) && (m_y < y) &&
+ (scroll > 0) && (clock() > sstart+CLOCKS_PER_SEC/24)) {
+ /* upward mouse scrolling */
+ scroll--;
+ sel = scroll;
+ redraw = TRUE;
+ sstart = clock();
+ }
+ else if ((m_x >= x-1) && (m_x < x+len-1) && (m_y >= y+num) &&
+ (scroll < count-num) && (clock() > sstart+CLOCKS_PER_SEC/24)) {
+ /* downward mouse scrolling */
+ scroll++;
+ sel = scroll+num-1;
+ redraw = TRUE;
+ sstart = clock();
+ }
+ }
+
+ ob = m_b;
+ }
+ }
+
+ mouse_off();
+ }
+}
+
+
+
+/* helper to remove a string from within another string */
+void strip_text(char *str, char *kill)
+{
+ char *s = strstr(str, kill);
+
+ if (s) {
+ if ((s > str) && (s[-1] == ' '))
+ strcpy(s-1, s+strlen(kill));
+ else if (s[strlen(kill)] == ' ')
+ strcpy(s, s+strlen(kill)+1);
+ else
+ strcpy(s, s+strlen(kill));
+ }
+}
+
+
+
+/* qsort() callback for sorting the driver list */
+int driver_cmp(const void *q1, const void *q2)
+{
+ DRIVER_INFO *d1 = (DRIVER_INFO *)q1;
+ DRIVER_INFO *d2 = (DRIVER_INFO *)q2;
+
+ return strcmp(d1->name, d2->name);
+}
+
+
+
+/* read the appended driver data */
+int read_driver_data()
+{
+ typedef unsigned long (*EXT_INIT_FUNC)(AF_DRIVER *af, unsigned long id);
+ EXT_INIT_FUNC ext_init;
+ FAF_CONFIG_DATA *cfg;
+ AF_DRIVER *af;
+ DRIVER_INFO *info;
+ PACKFILE *f;
+ char name[80];
+ unsigned long magic;
+ int type, size, ret;
+
+ f = pack_fopen("#", F_READ_PACKED);
+
+ if (!f)
+ return 1;
+
+ pack_mgetl(f);
+ pack_mgetl(f);
+
+ while (!pack_feof(f)) {
+ type = pack_mgetl(f);
+
+ if (type == DAT_FILE) {
+ f = pack_fopen_chunk(f, FALSE);
+ pack_mgetl(f);
+
+ info = &driver_info[num_drivers];
+
+ info->driver = NULL;
+ info->notes = NULL;
+
+ name[0] = 0;
+
+ while (!pack_feof(f)) {
+ type = pack_mgetl(f);
+
+ if (type == DAT_PROPERTY) {
+ type = pack_mgetl(f);
+ size = pack_mgetl(f);
+
+ if (type == DAT_NAME) {
+ pack_fread(name, size, f);
+ name[size] = 0;
+ }
+ else
+ pack_fseek(f, size);
+ }
+ else {
+ f = pack_fopen_chunk(f, FALSE);
+
+ if (strcmp(name, "VBEAF_DRV") == 0) {
+ info->driver_size = f->todo;
+ info->driver = malloc(info->driver_size);
+ pack_fread(info->driver, info->driver_size, f);
+ }
+ else if (strcmp(name, "NOTES_TXT") == 0) {
+ info->notes_size = f->todo;
+ info->notes = malloc(info->notes_size);
+ pack_fread(info->notes, info->notes_size, f);
+ }
+
+ f = pack_fclose_chunk(f);
+ }
+ }
+
+ if ((info->driver) && (info->notes)) {
+ strcpy(info->name, info->driver->OemVendorName);
+
+ strip_text(info->name, "FreeBE/AF");
+ strip_text(info->name, "driver");
+ strip_text(info->name, FREEBE_VERSION);
+
+ info->present = FALSE;
+ info->accel = FALSE;
+ info->config = 0;
+
+ af = malloc(info->driver_size);
+
+ if (af) {
+ memcpy(af, info->driver, info->driver_size);
+
+ if (af->OemExt) {
+ ext_init = (EXT_INIT_FUNC)((long)af + (long)af->OemExt);
+ magic = ext_init(af, FAFEXT_INIT);
+
+ if (((magic&0xFFFF0000) == FAFEXT_MAGIC) && (isdigit((magic>>8)&0xFF)) && (isdigit(magic&0xFF))) {
+ cfg = af->OemExt(af, FAFEXT_CONFIG);
+
+ if (cfg) {
+ while (cfg->id) {
+ if (cfg->id == FAF_CFG_FEATURES) {
+ info->config = (unsigned long)&cfg->value - (unsigned long)af;
+ break;
+ }
+
+ cfg++;
+ }
+ }
+ }
+ }
+
+ asm (
+ " call *%2 "
+
+ : "=&a" (ret)
+ : "b" (af),
+ "rm" (((long)af + (long)af->PlugAndPlayInit))
+ : "memory"
+ );
+
+ if (ret == 0) {
+ info->present = TRUE;
+ info->accel = ((af->Attributes & afHaveAccel2D) != 0);
+ }
+
+ free(af);
+ }
+
+ num_drivers++;
+ }
+
+ f = pack_fclose_chunk(f);
+ }
+ else if (type == DAT_PROPERTY) {
+ pack_mgetl(f);
+ size = pack_mgetl(f);
+ pack_fseek(f, size);
+ }
+ else {
+ size = pack_mgetl(f);
+ pack_fseek(f, size+4);
+ }
+ }
+
+ pack_fclose(f);
+
+ if (num_drivers > 1)
+ qsort(driver_info, num_drivers, sizeof(DRIVER_INFO), driver_cmp);
+
+ return 0;
+}
+
+
+
+/* detects what VBE/AF driver is currently installed */
+int check_current_driver()
+{
+ static char *options[] =
+ {
+ "Overwrite existing driver",
+ "Backup c:\\vbeaf.drv to c:\\vbeaf.old",
+ "Abort installation",
+ NULL
+ };
+
+ AF_DRIVER driver;
+ PACKFILE *f;
+
+ f = pack_fopen(VBEAF_FILENAME, F_READ);
+
+ if (!f) {
+ strcpy(current_driver_name, "{none}");
+ strcpy(current_driver_copyright, "");
+ return 0;
+ }
+
+ pack_fread(&driver, sizeof(driver), f);
+ pack_fclose(f);
+
+ strcpy(current_driver_name, driver.OemVendorName);
+ strcpy(current_driver_copyright, driver.OemCopyright);
+
+ if (strstr(current_driver_name, "FreeBE/AF"))
+ return 0;
+
+ draw_box(60, 16);
+
+ text_pos(12, screen_h/2-6);
+ text_str("Existing VBE/AF driver detected:");
+
+ text_color(0x74);
+
+ text_pos(16, screen_h/2-4);
+ text_clamp(current_driver_name, 48);
+
+ text_pos(16, screen_h/2-3);
+ text_clamp(current_driver_copyright, 48);
+
+ text_color(0x71);
+
+ text_pos(12, screen_h/2-1);
+ text_str("If this is one of the SciTech Display Doctor drivers,");
+
+ text_pos(12, screen_h/2);
+ text_str("it will be regenerated whenever you load UniVBE. You");
+
+ text_pos(12, screen_h/2+1);
+ text_str("will need to uninstall SDD before using FreeBE/AF.");
+
+ switch (get_selection(options, 0, 3, screen_h/2+3, FALSE)) {
+
+ case 0:
+ /* overwrite */
+ return 0;
+
+ case 1:
+ /* backup */
+ remove("c:\\vbeaf.old");
+ rename(VBEAF_FILENAME, "c:\\vbeaf.old");
+ strcpy(current_driver_name, "{none}");
+ strcpy(current_driver_copyright, "");
+ return 0;
+
+ default:
+ /* abort */
+ return 1;
+ }
+}
+
+
+
+/* displays the readme information */
+void text_viewer(char *text, int len)
+{
+ char buf[256];
+ int redraw;
+ int total, pos;
+ int line;
+ int c, i, l, p;
+ int oy;
+
+ total = 1;
+ pos = 0;
+
+ /* count number of lines */
+ for (i=0; i>8) {
+
+ case KEY_UP:
+ if (pos > 0)
+ pos--;
+ redraw = TRUE;
+ break;
+
+ case KEY_DOWN:
+ if (pos < total-screen_h)
+ pos++;
+ redraw = TRUE;
+ break;
+
+ case KEY_HOME:
+ pos = 0;
+ redraw = TRUE;
+ break;
+
+ case KEY_END:
+ pos = total-screen_h;
+ if (pos < 0)
+ pos = 0;
+ redraw = TRUE;
+ break;
+
+ case KEY_PGUP:
+ pos -= screen_h-1;
+ if (pos < 0)
+ pos = 0;
+ redraw = TRUE;
+ break;
+
+ case KEY_PGDN:
+ pos += screen_h-1;
+ if (pos > total-screen_h)
+ pos = total-screen_h;
+ if (pos < 0)
+ pos = 0;
+ redraw = TRUE;
+ break;
+
+ case KEY_ESC:
+ case KEY_ENTER:
+ case KEY_SPACE:
+ return;
+ }
+ }
+ else {
+ /* process mouse input */
+ oy = m_y;
+
+ mouse_read();
+
+ if (m_b)
+ return;
+
+ if (m_y != oy) {
+ pos += m_y-oy;
+ if (pos > total-screen_h)
+ pos = total-screen_h;
+ if (pos < 0)
+ pos = 0;
+ mouse_move(40, screen_h/2);
+ redraw = TRUE;
+ }
+ }
+ }
+ }
+}
+
+
+
+/* allows the user to edit the driver configuration */
+void edit_config(unsigned long *features, unsigned long orig_features)
+{
+ static char *flist[] =
+ {
+ "*Linear Framebuffer",
+ "*Banked Framebuffer",
+ "*Hardware Cursor",
+ "*DrawScan()",
+ "*DrawPattScan()",
+ "*DrawColorPattScan()",
+ "*DrawScanList()",
+ "*DrawPattScanList()",
+ "*DrawColorPattScanList()",
+ "*DrawRect()",
+ "*DrawPattRect()",
+ "*DrawColorPattRect()",
+ "*DrawLine()",
+ "*DrawStippleLine()",
+ "*DrawTrap()",
+ "*DrawTri()",
+ "*DrawQuad()",
+ "*PutMonoImage()",
+ "*PutMonoImageLin()",
+ "*PutMonoImageBM()",
+ "*BitBlt()",
+ "*BitBltSys()",
+ "*BitBltLin()",
+ "*BitBltBM()",
+ "*SrcTransBlt()",
+ "*SrcTransBltSys()",
+ "*SrcTransBltLin()",
+ "*SrcTransBltBM()",
+ "Go Back",
+ NULL
+ };
+
+ static int sel = 0;
+ int virgin = TRUE;
+ char *list[34];
+ int index[32];
+ int num_options, n, i;
+
+ num_options = 0;
+
+ for (n=0; n<(int)(sizeof(flist)/sizeof(char *)-2); n++) {
+ if (orig_features & (1<= num_options)
+ sel = 0;
+
+ n = MIN(num_options, screen_h*4/7);
+
+ draw_box(40, n+2);
+
+ for(ever) {
+ i = get_selection(list, sel, n, screen_h/2-n/2-1, !virgin);
+ if (i >= 0)
+ sel = i;
+
+ if ((i >= 0) && (i < num_options-1)) {
+ *features ^= (1<config)
+ *((unsigned long *)((unsigned long)info->driver+info->config)) = features;
+
+ pack_fwrite(info->driver, info->driver_size, f);
+ pack_fclose(f);
+
+ if (info->config)
+ *((unsigned long *)((unsigned long)info->driver+info->config)) = orig_features;
+
+ return TRUE;
+}
+
+
+
+/* installs a new driver */
+int got_card(DRIVER_INFO *info)
+{
+ static char *options[] =
+ {
+ "View implementation notes",
+ "Configure",
+ "Go Back",
+ "Quit",
+ NULL
+ };
+
+ int sel = 0;
+ unsigned long features = 0;
+ unsigned long orig_features = 0;
+
+ strcpy(current_driver_name, info->driver->OemVendorName);
+ strcpy(current_driver_copyright, info->driver->OemCopyright);
+
+ if (info->config) {
+ features = *((unsigned long *)((unsigned long)info->driver+info->config));
+ orig_features = features;
+ }
+
+ if (!install_driver(info, features, orig_features))
+ return FALSE;
+
+ for(ever) {
+ draw_box(60, 11);
+
+ text_pos(16, screen_h/2-3);
+ text_clamp(info->driver->OemVendorName, 48);
+ text_pos(16, screen_h/2-2);
+ text_str("has been installed onto your system.");
+
+ sel = get_selection(options, sel, 4, screen_h/2, FALSE);
+
+ switch (sel) {
+
+ case 0:
+ /* view notes */
+ text_viewer(info->notes, info->notes_size);
+ break;
+
+ case 1:
+ /* configure */
+ if (info->config) {
+ edit_config(&features, orig_features);
+ install_driver(info, features, orig_features);
+ }
+ else {
+ draw_box(60, 4);
+ text_pos(16, screen_h/2-1);
+ text_str("Sorry, this driver does not support the");
+ text_pos(16, screen_h/2);
+ text_str("FreeBE/AF configuration mechanism!");
+ input_pause();
+ }
+ break;
+
+ case 3:
+ /* quit */
+ return TRUE;
+
+ default:
+ /* back */
+ return FALSE;
+ }
+ }
+}
+
+
+
+/* allows the user to select a driver */
+int choose_card()
+{
+ static int sel = 0;
+ char *options[MAX_DRIVERS+1];
+ int i, n;
+
+ for (i=0; i= 0) {
+ sel = i;
+ return got_card(&driver_info[sel]);
+ }
+
+ return FALSE;
+}
+
+
+
+/* displays the main selection menu */
+void main_menu()
+{
+ static char *options[] =
+ {
+ "Autodetect graphics hardware",
+ "Manually select a driver",
+ "Remove FreeBE/AF",
+ "Quit",
+ NULL
+ };
+
+ char old_name[80];
+ int sel = 0;
+ int i;
+
+ for(ever) {
+ draw_box(40, 8);
+
+ sel = get_selection(options, sel, 4, screen_h/2-3, FALSE);
+
+ switch (sel) {
+
+ case 0:
+ /* autodetect */
+ for (i=0; i= num_drivers) {
+ for (i=0; i= num_drivers) {
+ draw_box(60, 3);
+ text_pos(16, screen_h/2);
+ text_str("Error: unable to detect any supported hardware.");
+ input_pause();
+ }
+ }
+ break;
+
+ case 1:
+ /* manual selection */
+ if (choose_card())
+ return;
+ break;
+
+ case 2:
+ /* uninstall */
+ if (strstr(current_driver_name, "FreeBE/AF")) {
+ remove(VBEAF_FILENAME);
+ strcpy(old_name, current_driver_name);
+ strcpy(current_driver_name, "{none}");
+ strcpy(current_driver_copyright, "");
+ draw_box(60, 4);
+ text_pos(16, screen_h/2-1);
+ text_clamp(old_name, 48);
+ text_pos(16, screen_h/2);
+ text_str("has been removed from your system.");
+ input_pause();
+ }
+ else {
+ draw_box(60, 4);
+ text_pos(16, screen_h/2-1);
+ text_str("Error removing driver:");
+ text_pos(16, screen_h/2);
+ text_str("No FreeBE/AF driver is currently installed!");
+ input_pause();
+ }
+ break;
+
+ default:
+ /* quit */
+ return;
+ }
+ }
+}
+
+
+
+/* main program */
+int main()
+{
+ struct text_info info;
+
+ allegro_init();
+ install_keyboard();
+
+ if (read_driver_data() != 0) {
+ printf("Fatal error: driver data not present!\n");
+ return 1;
+ }
+
+ __djgpp_set_ctrl_c(0);
+ setcbrk(0);
+
+ gettextinfo(&info);
+ screen_h = info.screenheight;
+ _setcursortype(_NOCURSOR);
+
+ mouse_init();
+
+ if (check_current_driver() == 0)
+ main_menu();
+
+ clrscr();
+ _setcursortype(_NORMALCURSOR);
+
+ if (strcmp(current_driver_name, "{none}") == 0) {
+ textattr(0x04);
+ cputs("No VBE/AF driver is installed on your machine.");
+ }
+ else {
+ textattr(0x07);
+ cputs("Installed driver:\r\n\r\n");
+ textattr(0x02);
+ cputs(current_driver_name);
+ cputs("\r\n");
+ cputs(current_driver_copyright);
+ }
+
+ textattr(0x07);
+ cputs("\r\n\r\n");
+
+ return 0;
+}
+
diff --git a/mach64/driver.c b/mach64/driver.c
new file mode 100644
index 0000000..c1be64d
--- /dev/null
+++ b/mach64/driver.c
@@ -0,0 +1,1910 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * ATI mach64 accelerated driver.
+ *
+ * Written by Ove Kaaven
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include
+
+#include "vbeaf.h"
+
+/* [OK] if you don't like VESA and like accessing the mach64 BIOS directly
+ better, define this, kill the bugs, and report to me... */
+#undef REFUSE_VESA
+
+
+
+/* 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 WaitForFifo(AF_DRIVER *af, int entries);
+void WaitTillIdle(AF_DRIVER *af);
+void ResetEngine(AF_DRIVER *af);
+void InitEngine(AF_DRIVER *af, int width, int height, int bpp);
+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 BitBlt(AF_DRIVER *af, long left, long top, 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 DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2);
+
+
+
+/* if you need some video memory for internal use by the accelerator
+ * code (for example storing pattern data), you can define this value to
+ * reserve room for yourself at the very end of the memory space, that
+ * the application will not be allowed to use.
+ */
+#define RESERVED_VRAM 0
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* at startup we use the get_vesa_info() helper function to find out
+ * what resolutions the VESA driver provides for this card, storing them
+ * in a table for future use. In a real driver you would replace this
+ * VESA code with a static list of modes and their attributes, because
+ * you would know right from the start what modes are possible on your
+ * card.
+ */
+
+typedef struct VIDEO_MODE
+{
+ int vesa_num;
+ int bios_num;
+ int w;
+ int h;
+ int bpp;
+ int redsize;
+ int redpos;
+ int greensize;
+ int greenpos;
+ int bluesize;
+ int bluepos;
+ int rsvdsize;
+ int rsvdpos;
+} VIDEO_MODE;
+
+
+#define MAX_MODES 128
+
+/* [OK] we'll ignore the 4-bit (16-color) modes */
+
+/* [OK] the idea of a mode list *and* VESA mode inquiry is that
+ certain modes seems to be available only through VESA (320x200, 640x400),
+ and some only through the mach64 BIOS (1600x1200, 32bpp modes) */
+
+VIDEO_MODE mode_list[MAX_MODES]={
+ {0x100, 0, 640, 400, 8},
+ {0x101,0x12C2, 640, 480, 8},
+ {0x103,0x6AC2, 800, 600, 8},
+ {0x105,0x55C2,1024, 768, 8},
+ {0x107,0x83C2,1280,1024, 8},
+ {0x110,0x12C3, 640, 480,15,5,10,5,5,5,0,0,0},
+ {0x111,0x12C4, 640, 480,16,5,11,6,5,5,0,0,0},
+ {0x112,0x12C5, 640, 480,24,8,16,8,8,8,0,0,0},
+ {0x113,0x6AC3, 800, 600,15,5,10,5,5,5,0,0,0},
+ {0x114,0x6AC4, 800, 600,16,5,11,6,5,5,0,0,0},
+/* [OK] Tim Riemann reported these >1MB modes (and the 0x107 above) */
+ {0x115,0x6AC5, 800, 600,24,8,16,8,8,8,0,0,0},
+ {0x116,0x55C3,1024, 768,15,5,10,5,5,5,0,0,0},
+ {0x117,0x55C4,1024, 768,16,5,11,6,5,5,0,0,0},
+ {0x118,0x55C5,1024, 768,24,8,16,8,8,8,0,0,0},
+ {0x119,0x83C3,1280,1024,15,5,10,5,5,5,0,0,0},
+ {0x11A,0x83C4,1280,1024,16,5,11,6,5,5,0,0,0},
+ {0x11B,0x83C5,1280,1024,24,8,16,8,8,8,0,0,0},
+/* [OK] nobody has reported VESA mode numbers for the following yet */
+/* [OK] ...are there any at all? anyone want to report on these? */
+/* [OK] 1600x1200 modes */
+ { 0,0x84C2,1600,1200, 8},
+ { 0,0x84C3,1600,1200,15,5,10,5,5,5,0,0,0},
+ { 0,0x84C4,1600,1200,16,5,11,6,5,5,0,0,0},
+ { 0,0x84C5,1600,1200,24,8,16,8,8,8,0,0,0},
+/* [OK] 32 bpp modes (mostly guesswork) */
+ { 0,0x12C6, 640, 480,32,8,16,8,8,8,0,0,0},
+ { 0,0x6AC6, 800, 600,32,8,16,8,8,8,0,0,0},
+ { 0,0x55C6,1024, 768,32,8,16,8,8,8,0,0,0},
+ { 0,0x83C6,1280,1024,32,8,16,8,8,8,0,0,0},
+ { 0,0x84C6,1600,1200,32,8,16,8,8,8,0,0,0}
+/* [OK] if VESA mode numbers do not exist, I may have to use bios_num */
+};
+
+short available_modes[MAX_MODES+1] = {
+ 1,2,3,4,5,6,7,8,9,10,
+ 11,12,13,14,15,16,17,
+/* 18,19,20,21,22,23,24,25,26, */
+ -1};
+
+int num_modes = 17;
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_linear;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+int af_fore_mix;
+int af_back_mix;
+
+unsigned mach64_dpmix, mach64_dpsrc;
+unsigned mach64_dcntl, mach64_scntl;
+
+/* register addresses */
+int mach64_floating, mach64_iobase;
+int mach64_wpsel, mach64_rpsel, mach64_offpitch;
+int mach64_dacrg, mach64_intr;
+
+#define ioOFFPITCH 0x05
+#define ioINTCNTL 0x06
+#define ioGENCNTL 0x07
+#define ioSCRATCH0 0x10
+#define ioSCRATCH1 0x11
+#define ioBUSCNTL 0x13
+#define ioWPSEL 0x15
+#define ioRPSEL 0x16
+#define ioDACREGS 0x17
+#define ioDACCNTL 0x18
+#define ioGTCNTL 0x19
+
+#define mmOFFPITCH 0x05
+#define mmINTCNTL 0x06
+#define mmGENCNTL 0x07
+#define mmSCRATCH0 0x20
+#define mmSCRATCH1 0x21
+#define mmBUSCNTL 0x28
+#define mmWPSEL 0x2D
+#define mmRPSEL 0x2E
+#define mmDACREGS 0x30
+#define mmDACCNTL 0x31
+#define mmGTCNTL 0x34
+#define HWCURSOR_ENABLE 0x80
+#define ENGINE_ENABLE 0x100
+
+#define mmDOFFPTCH 0x40
+#define mmDX 0x41
+#define mmDY 0x42
+#define mmDYX 0x43
+#define mmDWDTH 0x44
+#define mmDHT 0x45
+#define mmDHTWDTH 0x46
+#define mmDXWDTH 0x47
+#define mmDBRSLEN 0x48
+#define mmDBRSERR 0x49
+#define mmDBRSINC 0x4A
+#define mmDBRSDEC 0x4B
+#define mmDCNTL 0x4C
+#define DC_X_R2L 0x00
+#define DC_X_L2R 0x01
+#define DC_Y_B2T 0x00
+#define DC_Y_T2B 0x02
+#define DC_X_MAJ 0x00
+#define DC_Y_MAJ 0x04
+#define DC_X_TILE 0x08
+#define DC_Y_TILE 0x10
+#define DC_LAST_P 0x20
+#define DC_POLY 0x40
+#define DC_R_24 0x80
+
+#define mmSOFFPTCH 0x60
+#define mmSX 0x61
+#define mmSY 0x62
+#define mmSYX 0x63
+#define mmSWDTH1 0x64
+#define mmSHT1 0x65
+#define mmSHTWDTH1 0x66
+#define mmSXSTRT 0x67
+#define mmSYSTRT 0x68
+#define mmSYXSTRT 0x69
+#define mmSWDTH2 0x6A
+#define mmSHT2 0x6B
+#define mmSHTWDTH2 0x6C
+#define mmSCNTL 0x6D
+#define SC_PATT 0x01
+#define SC_ROT 0x02
+#define SC_LIN 0x04
+#define SC_BYTE_A 0x08
+#define SC_LX_R2L 0x00
+#define SC_LX_L2R 0x10
+
+#define mmHOSTCNTL 0x90
+
+#define mmPATREG0 0xA0
+#define mmPATREG1 0xA1
+#define mmPATCNTL 0xA2
+#define PC_MONO 0x01
+#define PC_C4x2 0x02
+#define PC_C8x1 0x04
+
+#define mmSCLEFT 0xA8
+#define mmSCRIGHT 0xA9
+#define mmSCLTRT 0xAA
+#define mmSCTOP 0xAB
+#define mmSCBOTTOM 0xAC
+#define mmSCTPBT 0xAD
+
+#define mmDPBGCOL 0xB0
+#define mmDPFGCOL 0xB1
+#define mmDPWRMSK 0xB2
+#define mmDPCHNMSK 0xB3
+#define mmPIXWDTH 0xB4
+#define PW_1 0
+#define PW_4 1
+#define PW_8 2
+#define PW_15 3
+#define PW_16 4
+#define PW_32 6
+#define PW_MSB 0x00000000
+#define PW_LSB 0x01000000
+#define mmDPMIX 0xB5
+#define mmDPSRC 0xB6
+#define DS_BGCOL 0x00
+#define DS_FGCOL 0x01
+#define DS_HOST 0x02
+#define DS_BLIT 0x03
+#define DS_PATT 0x04
+#define DSM_TRUE 0x00000
+#define DSM_PATT 0x10000
+#define DSM_HOST 0x20000
+#define DSM_BLIT 0x30000
+
+#define mmCCMPCLR 0xC0
+#define mmCCMPMSK 0xC1
+#define mmCCMPCNTL 0xC2
+#define CC_FALSE 0x00
+#define CC_TRUE 0x01
+#define CC_NOTEQ 0x04
+#define CC_EQUAL 0x05
+#define CC_DST 0x00000000
+#define CC_SRC 0x01000000
+
+#define mmFIFOSTAT 0xC4
+#define FIFO_ERR 0x80000000
+#define mmGUISTAT 0xCE
+#define ENGINE_BUSY 1
+#define mmCNTXMASK 0xC8
+#define mmCNTXLDCT 0xCB
+#define mmTRAJCNTL 0xCC
+#define mmGUISTAT 0xCE
+
+
+/* [OK] don't forget "volatile" if you need to do any loops,
+ like in WaitForFifo and WaitTillIdle (had some trouble with that) */
+#define mm_port(x) (((volatile unsigned long*)(af->IOMemMaps[0]))[x])
+
+/* [OK] this routine is adapted from Allegro's ati.c: */
+/* get_mach64_port:
+ * Calculates the port address for accessing a specific mach64 register.
+ */
+static int get_mach64_port(int io_sel, int mm_sel)
+{
+ if (mach64_floating) {
+ return (mm_sel << 2) + mach64_iobase;
+ }
+ else {
+ return (io_sel << 10) + mach64_iobase;
+ }
+}
+
+/*
+
+taken from mach64 example code, I don't understand what this macro
+really does, but I interpret it in this way
+
+#define GET24BPPROTATION(x) (unsigned long)(((x * 3) / 4) % 6)
+
+r g b r g b r g b r g b r g b r g b r g b r g b
+0 1 2 3 4 5 6 7
+---0--- ---1--- ---2--- ---3--- ---4--- ---5---
+
+though it doesn't seem very logical to have a "rotation" value do this
+*/
+
+#define m64_rot24(x) (DC_R_24|((((x)/4)%6)<<8))
+
+
+/* note about VBE/AF multiple page modes: the API supports any number of
+ * video memory pages, one of which is "active" (being drawn onto), while
+ * the other is visible on your monitor. Allegro doesn't actually use
+ * this functionality, so you may safely leave it out and just reject
+ * any mode set requests with a numBuffers value greater than one, but
+ * that might upset other VBE/AF applications if they depend on this
+ * functionality. To support multiple pages, you must offset all the
+ * hardware drawing operations so their coordinate system is relative
+ * to the active page. You must also maintain an offset from the start
+ * of vram to the start of the active page in the OriginOffset of the
+ * driver structure, and adjust the OffscreenStartY and OffscreenEndY
+ * values so they will refer to the same offscreen memory region regardless
+ * of the current accelerator coordinate system. This is all handled by the
+ * SetActiveBuffer() function below, so in practice you can simply add
+ * af_active_page*af_height onto the input Y coordinate of any accelerator
+ * drawing funcs, and multiple page modes should work correctly.
+ */
+
+
+
+#ifndef REFUSE_VESA
+/* 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)
+{
+ int chk;
+
+ if (num_modes >= MAX_MODES)
+ return;
+
+ if ((bpp != 8) && (bpp != 15) && (bpp != 16) && (bpp != 24) && (bpp != 32))
+ return;
+
+ /* [OK] make sure mode is not already in list */
+ for (chk=0; chkAvailableModes = available_modes;
+
+ /* amount of video memory in K */
+ af->TotalMemory = vram_size;
+
+ /* driver attributes (see definitions in vbeaf.h) */
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer |
+ afHaveAccel2D |
+ afHaveROP2);
+
+ if (aperture_addr)
+ af->Attributes |= afHaveLinearBuffer;
+
+ /* banked memory size and location: zero if not supported */
+ af->BankSize = 32;
+ af->BankedBasePtr = 0xA0000;
+
+ /* linear framebuffer size and location: zero if not supported */
+ if (aperture_addr) {
+ af->LinearSize = MIN(vram_size, (int)aperture_size - 0x400);
+ af->LinearBasePtr = aperture_addr;
+ }
+ else {
+ af->LinearSize = 0;
+ af->LinearBasePtr = 0;
+ }
+
+ /* list which ports we are going to access (only needed under Linux) */
+ af->IOPortsTable = ports_table;
+
+ /* list physical memory regions that we need to access (zero for none) */
+ for (i=0; i<4; i++) {
+ af->IOMemoryBase[i] = 0;
+ af->IOMemoryLen[i] = 0;
+ }
+ /* [OK] the mach64 MMIO registers are at end of aperture */
+ if (aperture_addr)
+ af->IOMemoryBase[0] = aperture_addr + aperture_size - 0x400;
+ else
+ af->IOMemoryBase[0] = 0xC0000 - 0x400;
+ af->IOMemoryLen[0] = 0x400;
+
+ /* driver state variables (initialised later during the mode set) */
+ af->BufferEndX = 0;
+ af->BufferEndY = 0;
+ af->OriginOffset = 0;
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+
+ /* relocatable bank switcher (not required by Allegro) */
+ af->SetBank32 = SetBank32;
+ af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
+
+ /* extension functions */
+ af->SupplementalExt = ExtStub;
+
+ /* device driver functions */
+ 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->EnableStereoMode = NULL;
+ af->SetPaletteData = SetPaletteData;
+ af->SetGammaCorrectData = NULL;
+ af->SetBank = SetBank;
+
+ /* hardware cursor functions (not supported: not used by Allegro) */
+ af->SetCursor = NULL;
+ af->SetCursorPos = NULL;
+ af->SetCursorColor = NULL;
+ af->ShowCursor = NULL;
+
+ /* wait until the accelerator hardware has finished drawing */
+ af->WaitTillIdle = WaitTillIdle;
+
+ /* on some cards the CPU cannot access the framebuffer while it is in
+ * hardware drawing mode. If this is the case, you should fill in these
+ * functions with routines to switch in and out of the accelerator mode.
+ * The application will call EnableDirectAccess() whenever it is about
+ * to write to the framebuffer directly, and DisableDirectAccess()
+ * before it calls any hardware drawing routines. If this arbitration is
+ * not required, leave these routines as NULL.
+ */
+ af->EnableDirectAccess = NULL;
+ af->DisableDirectAccess = NULL;
+
+ /* sets the hardware drawing mode (solid, XOR, etc). Required. */
+ af->SetMix = SetMix;
+
+ /* pattern download functions. May be NULL if patterns not supported */
+ af->Set8x8MonoPattern = Set8x8MonoPattern;
+#if 0
+ af->Set8x8ColorPattern = Set8x8ColorPattern;
+ af->Use8x8ColorPattern = Use8x8ColorPattern;
+#endif
+
+ /* not supported: not used by Allegro */
+ af->SetLineStipple = NULL;
+ af->SetLineStippleCount = NULL;
+
+ /* not supported. There really isn't much point in this function because
+ * a lot of hardware can't do clipping at all, and even when it can there
+ * are usually problems with very large or negative coordinates. This
+ * means that a software clip is still required, so you may as well
+ * ignore this routine.
+ */
+ af->SetClipRect = NULL;
+
+ /* DrawScan() is required: patterned versions may be NULL */
+ af->DrawScan = DrawScan;
+ af->DrawPattScan = DrawPattScan;
+#if 0
+ af->DrawColorPattScan = DrawColorPattScan;
+#endif
+
+ /* not supported: not used by Allegro */
+ af->DrawScanList = NULL;
+ af->DrawPattScanList = NULL;
+ af->DrawColorPattScanList = NULL;
+
+ /* rectangle filling: may be NULL */
+ af->DrawRect = DrawRect;
+ af->DrawPattRect = DrawPattRect;
+#if 0
+ af->DrawColorPattRect = DrawColorPattRect;
+#endif
+
+ /* not supported: not used by Allegro */
+ af->DrawLine = NULL;
+ af->DrawStippleLine = NULL;
+ af->DrawTrap = NULL;
+ af->DrawTri = NULL;
+ af->DrawQuad = NULL;
+ af->PutMonoImage = NULL;
+ af->PutMonoImageLin = NULL;
+ af->PutMonoImageBM = NULL;
+
+ /* blitting within the video memory (may be NULL) */
+ af->BitBlt = BitBlt;
+
+ /* not supported: not used by Allegro */
+ af->BitBltSys = NULL;
+ af->BitBltLin = NULL;
+ af->BitBltBM = NULL;
+
+ /* masked blitting within the video memory (may be NULL) */
+ af->SrcTransBlt = NULL;
+
+ /* not supported: not used by Allegro */
+ af->SrcTransBltSys = NULL;
+ af->SrcTransBltLin = NULL;
+ af->SrcTransBltBM = NULL;
+ af->DstTransBlt = NULL;
+ af->DstTransBltSys = NULL;
+ af->DstTransBltLin = NULL;
+ af->DstTransBltBM = NULL;
+ af->StretchBlt = NULL;
+ af->StretchBltSys = NULL;
+ af->StretchBltLin = NULL;
+ af->StretchBltBM = NULL;
+ af->SrcTransStretchBlt = NULL;
+ af->SrcTransStretchBltSys = NULL;
+ af->SrcTransStretchBltLin = NULL;
+ af->SrcTransStretchBltBM = NULL;
+ af->DstTransStretchBlt = NULL;
+ af->DstTransStretchBltSys = NULL;
+ af->DstTransStretchBltLin = NULL;
+ af->DstTransStretchBltBM = NULL;
+ af->SetVideoInput = NULL;
+ af->SetVideoOutput = NULL;
+ af->StartVideoFrame = NULL;
+ af->EndVideoFrame = NULL;
+
+ 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)
+{
+ return 0;
+}
+
+
+
+/* FreeBEX:
+ * Returns an interface structure for the requested FreeBE/AF extension.
+ */
+void *FreeBEX(AF_DRIVER *af, unsigned long id)
+{
+ switch (id) {
+
+ 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, bytes_per_scanline;
+
+ 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;
+
+#ifdef REFUSE_VESA
+ if (!info->bios_num) return -1;
+#endif
+
+ /* copy data across from our stored list of mode attributes */
+ modeInfo->Attributes = af->Attributes;
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ bytes_per_scanline = info->w * BYTES_PER_PIXEL(info->bpp);
+
+ /* available pages of video memory */
+ modeInfo->MaxBuffers = (af->TotalMemory*1024 - RESERVED_VRAM) /
+ (bytes_per_scanline * info->h);
+
+ /* maximum virtual scanline length in both bytes and pixels. How wide
+ * this can go will very much depend on the card: 1024 is pretty safe
+ * on anything, but you will want to allow larger limits if the card
+ * is capable of them.
+ */
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+
+ /* for banked video modes, fill in these variables: */
+ modeInfo->BytesPerScanLine = 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 = 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)
+{
+ int linear = ((mode & 0x4000) != 0);
+ int noclear = ((mode & 0x8000) != 0);
+ long available_vram;
+ long used_vram;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo */
+ if (mode & 0x400)
+ 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) && (!af->Attributes&afHaveLinearBuffer))
+ return -1;
+
+#ifndef REFUSE_VESA
+ if (info->vesa_num) {
+ /* call VESA to set the mode */
+ r.x.ax = 0x4F02;
+ r.x.bx = info->vesa_num;
+#if 0
+ /* [OK] the mach64 BIOS is VESA 1.2 which can't handle LFB itself */
+ if (linear)
+ r.x.bx |= 0x4000;
+#endif
+ if (noclear)
+ r.x.bx |= 0x8000;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+ } else {
+#endif
+ /* [OK] call mach64 BIOS to set the mode */
+ r.x.ax = 0xA002;
+ r.x.cx = info->bios_num;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+#ifndef REFUSE_VESA
+ }
+#endif
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX < info->w)
+ virtualX = info->w;
+ /* [OK] enforce necessary alignment */
+ virtualX=virtualX&~7;
+
+ outportl(mach64_offpitch,
+ (inportl(mach64_offpitch) & 0xFFFFF) | (virtualX << 19));
+
+ *bytesPerLine = virtualX*BYTES_PER_PIXEL(info->bpp);
+
+ /* [OK] enable the mach64 linear aperture */
+ if (linear) {
+ r.x.ax = 0xA005;
+ r.x.cx = 1;
+ rm_int(0x10, &r);
+ }
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_linear = linear;
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_bank = -1;
+
+ af_fore_mix = AF_REPLACE_MIX;
+ af_back_mix = AF_FORE_MIX;
+
+ /* [OK] provide acceleration where possible */
+ switch (af_bpp) {
+ case 8:
+ case 15:
+ case 16:
+ case 32:
+ af->SrcTransBlt = SrcTransBlt;
+ af->DrawLine = DrawLine;
+ break;
+ default: /* 24bpp */
+ af->SrcTransBlt = NULL; /* haven't figured how to do this in 24bpp */
+ af->DrawLine = NULL; /* would have to be done pixel-by-pixel */
+ break;
+ }
+
+ /* return framebuffer dimensions to the application */
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 - RESERVED_VRAM;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ /* [OK] load mode parameters into the graphics coprocessor */
+ InitEngine(af, virtualX, (numBuffers < 2) ? af->OffscreenEndY : af_height, info->bpp);
+
+#ifndef REFUSE_VESA
+ if (!info->vesa_num)
+#endif
+ if (!noclear) {
+ DrawRect(af, 0, 0, 0, info->w, af_height);
+ WaitTillIdle(af);
+ }
+
+ return 0;
+}
+
+
+
+/* RestoreTextMode:
+ * Returns to text mode, shutting down the accelerator hardware.
+ */
+void RestoreTextMode(AF_DRIVER *af)
+{
+ RM_REGS r;
+
+ /* [OK] disable aperture, just in case */
+ r.x.ax = 0xA005;
+ r.x.cx = 0;
+ rm_int(0x10, &r);
+
+ /* [OK] back to where it all began */
+ 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)
+{
+ if (waitVRT != -1) {
+ long a = x + ((y + af_visible_page*af_height) * af_width);
+
+ a *= BYTES_PER_PIXEL(af_bpp);
+
+ if (waitVRT) {
+ do {
+ } while (inportb(mach64_intr) & 1);
+
+ do {
+ } while (!(inportb(mach64_intr) & 1));
+ }
+
+ outportl(mach64_offpitch,
+ (inportl(mach64_offpitch) & 0xFFF00000) | (a >> 3));
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(mach64_intr) & 1);
+
+ do {
+ } while (!(inportb(mach64_intr) & 1));
+ }
+
+ for (i=0; i> entries;
+#ifdef TEST
+ alarm(5);
+#endif
+ while ((mm_port(mmFIFOSTAT)&0xFFFF) > ent);
+#ifdef TEST
+ alarm(0);
+#endif
+}
+
+
+
+/* WaitTillIdle:
+ * Delay until the hardware controller has finished drawing.
+ */
+void WaitTillIdle(AF_DRIVER *af)
+{
+ WaitForFifo(af, 16);
+#ifdef TEST
+ alarm(5);
+#endif
+ while (mm_port(mmGUISTAT) & ENGINE_BUSY);
+#ifdef TEST
+ alarm(0);
+#endif
+}
+
+
+
+/* ResetEngine:
+ * [OK] Reset the GUI engine and clear any errors.
+ */
+void ResetEngine(AF_DRIVER *af)
+{
+ int cntl_reg;
+
+ /* reset engine */
+ cntl_reg = get_mach64_port(ioGTCNTL, mmGTCNTL);
+ outportl(cntl_reg, inportl(cntl_reg) & 0xFFFFFEFF);
+ /* enable engine */
+ outportl(cntl_reg, inportl(cntl_reg) | ENGINE_ENABLE);
+ /* clear any errors */
+ cntl_reg = get_mach64_port(ioBUSCNTL, mmBUSCNTL);
+ outportl(cntl_reg, (inportl(cntl_reg) & 0xFF00FFFF) | 0x00AE0000);
+}
+
+
+
+unsigned mach64_mix[]={
+ 7, /* REPLACE_MIX */
+ 12, /* AND_MIX */
+ 11, /* OR_MIX */
+ 5, /* XOR_MIX */
+ 3, /* NOP_MIX */
+
+ 7,7,7,7,7,7,7,7,7,7,7, /* padding */
+
+ /* ROP2 conversion */
+ /* S:1100 */
+ /* D:1010 */
+ /* ---- */
+ 1, /* 0000 BLACK aka ZERO */
+ 15, /* 0001 NOTMERGESRC aka NOT_D_AND_NOT_S */
+ 14, /* 0010 MASKNOTSRC aka D_AND_NOT_S */
+ 4, /* 0011 NOTCOPYSRC aka NOT_S */
+ 13, /* 0100 MASKSRCNOT aka NOT_D_AND_S */
+ 0, /* 0101 NOT aka NOT_D */
+ 5, /* 0110 XORSRC aka D_XOR_S */
+ 8, /* 0111 NOTMASKSRC aka NOT_D_OR_NOT_S */
+ 12, /* 1000 MASKSRC aka D_AND_S */
+ 6, /* 1001 NOTXORSRC aka NOT_D_XOR_S */
+ 3, /* 1010 NOP aka D */
+ 9, /* 1011 MERGENOTSRC aka D_OR_NOT_S */
+ 7, /* 1100 COPYSRC aka S */
+ 10, /* 1101 MERGESRCNOT aka NOT_D_OR_S */
+ 11, /* 1110 MERGESRC aka D_OR_S */
+ 2 /* 1111 WHITE aka ONE */
+
+/* the mach64 also supports a (S+D)/2 mix mode (hardware-accelerated
+ blending, cool) 0x17, but I don't think VBE/AF supports that... */
+};
+
+/* SetMix:
+ * Specifies the pixel mix mode to be used for hardware drawing functions
+ * (not the blit routines: they take an explicit mix parameter). Both
+ * parameters should both be one of the AF_mixModes enum defined in vbeaf.h.
+ *
+ * VBE/AF requires all drivers to support the REPLACE, AND, OR, XOR,
+ * and NOP mix types. This file implements all the required types, but
+ * Allegro only actually uses the REPLACE and XOR modes for scanline and
+ * rectangle fills, REPLACE mode for blitting and color pattern drawing,
+ * and either REPLACE or foreground REPLACE and background NOP for mono
+ * pattern drawing.
+ */
+void SetMix(AF_DRIVER *af, long foreMix, long backMix)
+{
+ af_fore_mix = foreMix;
+
+ if (backMix == AF_FORE_MIX)
+ af_back_mix = foreMix;
+ else
+ af_back_mix = backMix;
+
+ mach64_dpmix = (mach64_mix[af_fore_mix]<<16) | mach64_mix[af_back_mix];
+
+ WaitForFifo(af, 1);
+ mm_port(mmDPMIX) = mach64_dpmix;
+}
+
+
+
+/* InitEngine:
+ * [OK] Loads the current mode parameters into the graphics coprocessor.
+ */
+void InitEngine(AF_DRIVER *af, int width, int height, int bpp)
+{
+ /* reset engine */
+ ResetEngine(af);
+
+ if (bpp == 24) {
+ /* [OK] the mach64 graphics coprocessor doesn't support 24bpp,
+ so it must be set to 8bpp, which means the width must be
+ adjusted accordingly */
+ width *= 3;
+ }
+
+ /* make sure the FIFO has room for our next 14 register loads */
+ WaitForFifo(af, 14);
+ /* full context mask */
+ mm_port(mmCNTXMASK) = 0xFFFFFFFF;
+ /* destination parameters */
+ mm_port(mmDOFFPTCH) = width << 19;
+ mm_port(mmDYX) = 0;
+ mm_port(mmDHT) = 0;
+ mm_port(mmDBRSERR) = 0;
+ mm_port(mmDBRSINC) = 0;
+ mm_port(mmDBRSDEC) = 0;
+ mach64_dcntl = DC_LAST_P|DC_Y_T2B|DC_X_L2R;
+ mm_port(mmDCNTL) = mach64_dcntl;
+ /* source parameters */
+ mm_port(mmSOFFPTCH) = width << 19;
+ mm_port(mmSYX) = 0;
+ mm_port(mmSHTWDTH1) = 0;
+ mm_port(mmSYXSTRT) = 0;
+ mm_port(mmSHTWDTH2) = 0;
+ mach64_scntl = SC_LX_L2R;
+ mm_port(mmSCNTL) = mach64_scntl;
+
+ /* 13 more register loads on their way */
+ WaitForFifo(af, 13);
+ /* host control */
+ mm_port(mmHOSTCNTL) = 0;
+ /* pattern */
+ mm_port(mmPATREG0) = 0;
+ mm_port(mmPATREG1) = 0;
+ mm_port(mmPATCNTL) = 0;
+ /* clipping */
+ mm_port(mmSCLEFT) = 0;
+ mm_port(mmSCTOP) = 0;
+ mm_port(mmSCBOTTOM) = height-1;
+ mm_port(mmSCRIGHT) = width-1;
+ /* colors */
+ mm_port(mmDPBGCOL) = 0;
+ mm_port(mmDPFGCOL) = 0xFFFFFFFF;
+ /* write mask */
+ mm_port(mmDPWRMSK) = 0xFFFFFFFF;
+ /* mix mode = replace */
+ mach64_dpmix = 7<<16 | 7;
+ mm_port(mmDPMIX) = mach64_dpmix;
+ /* foreground source */
+ mach64_dpsrc = DS_FGCOL<<8 | DS_BGCOL;
+ mm_port(mmDPSRC) = mach64_dpsrc;
+
+ /* 5 register loads left */
+ WaitForFifo(af, 5);
+ /* pixel masking */
+ mm_port(mmCCMPCLR) = 0;
+ mm_port(mmCCMPMSK) = 0xFFFFFFFF;
+ mm_port(mmCCMPCNTL) = 0;
+
+ /* bpp mode */
+ switch (bpp) {
+ case 4: /* just for completeness */
+ mm_port(mmPIXWDTH) = PW_4 << 16 | PW_4 << 8 | PW_4 | PW_LSB;
+ mm_port(mmDPCHNMSK) = 0x8888;
+ break;
+ case 15:
+ mm_port(mmPIXWDTH) = PW_15 << 16 | PW_15 << 8 | PW_15 | PW_LSB;
+ mm_port(mmDPCHNMSK) = 0x4210;
+ break;
+ case 16:
+ mm_port(mmPIXWDTH) = PW_16 << 16 | PW_16 << 8 | PW_16 | PW_LSB;
+ mm_port(mmDPCHNMSK) = 0x8410;
+ break;
+ case 32:
+ mm_port(mmPIXWDTH) = PW_32 << 16 | PW_32 << 8 | PW_32 | PW_LSB;
+ mm_port(mmDPCHNMSK) = 0x8080;
+ break;
+ default: /* 8bpp and 24bpp */
+ mm_port(mmPIXWDTH) = PW_8 << 16 | PW_8 << 8 | PW_8 | PW_LSB;
+ mm_port(mmDPCHNMSK) = 0x8080;
+ break;
+ }
+
+ /* wait for graphics coprocessor to swallow it all */
+ WaitTillIdle(af);
+}
+
+
+
+/* af_putpixel:
+ * Writes a pixel to the screen with the specified mix mode. This function
+ * is _not_ intended to be useful: it is grossly inefficient! It is just
+ * a helper for the example drawing routines below: these should of course
+ * be replaced by hardware specific code.
+ */
+void af_putpixel(AF_DRIVER *af, int x, int y, int c, int mix)
+{
+ long offset;
+ int bank;
+ int c2 = 0;
+ void *p;
+
+ y += af_active_page*af_height;
+ offset = y*af_width + x*BYTES_PER_PIXEL(af_bpp);
+
+ /* quit if this is a noop */
+ if (mix == AF_NOP_MIX)
+ return;
+
+ /* get pointer to vram */
+ if (af_linear) {
+ p = af->LinearMem + offset;
+ }
+ else {
+ p = af->BankedMem + (offset&0x7FFF);
+ bank = offset>>15; /* 32K granularity */
+ if (bank != af_bank) {
+ af->SetBank(af, bank);
+ af_bank = bank;
+ }
+ }
+
+ if (mix != AF_REPLACE_MIX) {
+ /* read destination pixel for mixing */
+ switch (af_bpp) {
+
+ case 8:
+ c2 = *((unsigned char *)p);
+ break;
+
+ case 15:
+ case 16:
+ c2 = *((unsigned short *)p);
+ break;
+
+ case 24:
+ c2 = *((unsigned long *)p) & 0xFFFFFF;
+ break;
+
+ case 32:
+ c2 = *((unsigned long *)p);
+ break;
+ }
+
+ /* apply logical mix modes */
+ switch (mix) {
+
+ case AF_AND_MIX:
+ c &= c2;
+ break;
+
+ case AF_OR_MIX:
+ c |= c2;
+ break;
+
+ case AF_XOR_MIX:
+ c ^= c2;
+ break;
+ }
+ }
+
+ /* write the pixel */
+ switch (af_bpp) {
+
+ case 8:
+ *((unsigned char *)p) = c;
+ break;
+
+ case 15:
+ case 16:
+ *((unsigned short *)p) = c;
+ break;
+
+ case 24:
+ *((unsigned short *)p) = c&0xFFFF;
+ *((unsigned char *)(p+2)) = c>>16;
+ break;
+
+ case 32:
+ *((unsigned long *)p) = c;
+ break;
+ }
+}
+
+
+
+/* af_getpixel:
+ * Reads a pixel from the screen. This function is _not_ intended to
+ * be useful: it is grossly inefficient! It is just a helper for the
+ * example drawing routines below: these should of course be replaced
+ * by hardware specific code.
+ */
+int af_getpixel(AF_DRIVER *af, int x, int y)
+{
+ long offset;
+ int bank;
+ void *p;
+
+ y += af_active_page*af_height;
+ offset = y*af_width + x*BYTES_PER_PIXEL(af_bpp);
+
+ /* get pointer to vram */
+ if (af_linear) {
+ p = af->LinearMem + offset;
+ }
+ else {
+ p = af->BankedMem + (offset&0x7FFF);
+ bank = offset>>15; /* 32K granularity */
+ if (bank != af_bank) {
+ af->SetBank(af, bank);
+ af_bank = bank;
+ }
+ }
+
+ /* read the pixel */
+ switch (af_bpp) {
+
+ case 8:
+ return *((unsigned char *)p);
+
+ case 15:
+ case 16:
+ return *((unsigned short *)p);
+
+ case 24:
+ return *((unsigned long *)p) & 0xFFFFFF;
+
+ case 32:
+ return *((unsigned long *)p);
+ }
+
+ return 0;
+}
+
+
+
+/* stored mono pattern data */
+unsigned char mono_pattern[8];
+
+
+
+/* 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)
+{
+ int i;
+
+ for (i=0; i<8; i++)
+ mono_pattern[i] = pattern[i];
+
+ WaitForFifo(af, 3);
+ mm_port(mmPATREG0) = ((unsigned long*)(&mono_pattern))[0];
+ mm_port(mmPATREG1) = ((unsigned long*)(&mono_pattern))[1];
+ mm_port(mmPATCNTL) = PC_MONO;
+}
+
+
+
+/* stored color pattern data */
+unsigned long color_pattern[8][64];
+unsigned long *current_color_pattern = color_pattern[0];
+
+/* [OK] I've disabled color patterns for now */
+
+/* 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).
+ *
+ * VBE/AF supports 8 different color patterns, which may be downloaded
+ * individually and then selected for use with the Use8x8ColorPattern()
+ * function. If the card is not able to cache these patterns in hardware,
+ * the driver is responsible for storing them internally and downloading
+ * the appropriate data when Use8x8ColorPattern() is called.
+ *
+ * Allegro only actually ever uses the first of these patterns, so
+ * you only need to bother about this if you want your code to work
+ * with other programs as well.
+ */
+void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
+{
+ int i;
+
+ for (i=0; i<64; i++)
+ color_pattern[index][i] = pattern[i];
+}
+
+
+
+/* Use8x8ColorPattern:
+ * Selects one of the patterns previously downloaded by Set8x8ColorPattern().
+ */
+void Use8x8ColorPattern(AF_DRIVER *af, int index)
+{
+ current_color_pattern = 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 (x2 < x1)
+ DrawRect(af, color, x2, y, x1-x2, 1);
+ else
+ DrawRect(af, color, x1, y, x2-x1, 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 (x2 < x1)
+ DrawPattRect(af, foreColor, backColor, x2, y, x1-x2, 1);
+ else
+ DrawPattRect(af, foreColor, backColor, x1, y, x2-x1, 1);
+}
+
+
+
+/* DrawColorPattScan:
+ * Fills a scanline using the current color pattern and mix mode.
+ */
+void DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2)
+{
+ int orig_bank = af_bank;
+ int patx, paty;
+
+ if (x2 < x1) {
+ int tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ while (x1 < x2) {
+ patx = x1&7;
+ paty = y&7;
+
+ af_putpixel(af, x1, y, current_color_pattern[paty*8+patx], af_fore_mix);
+
+ x1++;
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* 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)
+{
+ if (af_bpp == 24) {
+ left *= 3;
+ width *= 3;
+
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl | m64_rot24(left);
+ }
+
+ WaitForFifo(af, 5);
+ /* [OK] set color */
+ mm_port(mmDPFGCOL) = color;
+ /* [OK] draw rectangle */
+ mm_port(mmDX) = left;
+ mm_port(mmDY) = top + af_active_page*af_height;
+ mm_port(mmDHT) = height;
+ mm_port(mmDWDTH) = width;
+
+ if (af_bpp == 24) {
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl;
+ }
+}
+
+
+
+/* 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)
+{
+ WaitForFifo(af, 2);
+ /* [OK] set background color and source */
+ mm_port(mmDPBGCOL) = backColor;
+ /* [OK] I'm not quite sure about this...
+ I don't think it works, but I don't have a test program
+ anyone to test it for me? */
+ mm_port(mmDPSRC) = DSM_PATT | (DS_FGCOL<<8) | DS_BGCOL;
+
+ DrawRect(af, foreColor, left, top, width, height);
+
+ /* [OK] restore defaults */
+ WaitForFifo(af, 1);
+ mm_port(mmDPSRC) = mach64_dpsrc;
+}
+
+
+
+/* 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 orig_bank = af_bank;
+ int patx, paty;
+ int x, y;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* 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)
+{
+ if (af_bpp == 24) {
+ left *= 3;
+ width *= 3;
+ dstLeft *= 3;
+
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl | m64_rot24(dstLeft);
+ }
+
+ WaitForFifo(af, 2);
+
+ /* [OK] set blt source and mix mode */
+ mm_port(mmDPSRC) = (DS_BLIT<<8) | DS_BGCOL;
+ mm_port(mmDPMIX) = (mach64_mix[op]<<16) | mach64_mix[op];
+
+#if 0
+ if ((left+width > dstLeft) && (top+height > dstTop) &&
+ (dstLeft+width > left) && (dstTop+height > top) &&
+ ((dstTop > top) || ((dstTop == top) && (dstLeft > left)))) {
+#else
+ /* [OK] looks like the mach64 only needs to reverse the Y direction */
+ if ((top+height > dstTop) && (dstTop > top)) {
+#endif
+ /* have to do the copy backward */
+ WaitForFifo(af, 9);
+ mm_port(mmDCNTL) = (mach64_dcntl&~DC_Y_T2B)|DC_Y_B2T;
+
+ /* [OK] do the blit */
+ mm_port(mmSX) = left;
+ mm_port(mmSY) = top + height + af_active_page*af_height;
+ mm_port(mmSHT1) = height;
+ mm_port(mmSWDTH1) = width;
+
+ mm_port(mmDX) = dstLeft;
+ mm_port(mmDY) = dstTop + height + af_active_page*af_height;
+ mm_port(mmDHT) = height;
+ mm_port(mmDWDTH) = width;
+
+ /* [OK] restore defaults */
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl;
+ } else {
+ WaitForFifo(af, 8);
+
+ /* [OK] do the blit */
+ mm_port(mmSX) = left;
+ mm_port(mmSY) = top + af_active_page*af_height;
+ mm_port(mmSHT1) = height;
+ mm_port(mmSWDTH1) = width;
+
+ mm_port(mmDX) = dstLeft;
+ mm_port(mmDY) = dstTop + af_active_page*af_height;
+ mm_port(mmDHT) = height;
+ mm_port(mmDWDTH) = width;
+
+ if (af_bpp == 24) {
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl;
+ }
+ }
+
+ /* [OK] restore defaults */
+ WaitForFifo(af, 2);
+ mm_port(mmDPMIX) = mach64_dpmix;
+ mm_port(mmDPSRC) = mach64_dpsrc;
+}
+
+
+
+/* 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)
+{
+ /* [OK] note: this routine doesn't work in 24bpp for some reason,
+ so it is disabled at mode set */
+#if 0
+ if (af_bpp == 24) {
+ left *= 3;
+ width *= 3;
+ dstLeft *= 3;
+
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl | m64_rot24(dstLeft);
+ }
+#endif
+
+ WaitForFifo(af, 4);
+ /* [OK] set transparency color */
+ mm_port(mmCCMPCLR) = transparent;
+ mm_port(mmCCMPCNTL) = CC_EQUAL | CC_SRC;
+
+ /* [OK] set blt source and mix mode */
+ mm_port(mmDPSRC) = (DS_BLIT<<8) | DS_BLIT;
+ mm_port(mmDPMIX) = (mach64_mix[op]<<16) | mach64_mix[op];
+
+ WaitForFifo(af, 8);
+
+ /* [OK] do the blit */
+ mm_port(mmSX) = left;
+ mm_port(mmSY) = top + af_active_page*af_height;
+ mm_port(mmSHT1) = height;
+ mm_port(mmSWDTH1) = width;
+
+ mm_port(mmDX) = dstLeft;
+ mm_port(mmDY) = dstTop + af_active_page*af_height;
+ mm_port(mmDHT) = height;
+ mm_port(mmDWDTH) = width;
+
+ /* [OK] restore defaults */
+ WaitForFifo(af, 3);
+ mm_port(mmDPMIX) = mach64_dpmix;
+ mm_port(mmDPSRC) = mach64_dpsrc;
+ mm_port(mmCCMPCNTL) = 0;
+
+#if 0
+ if (af_bpp == 24) {
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl;
+ }
+#endif
+}
+
+void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2)
+{
+ /* [OK] note: this routine won't work in 24bpp, so it is disabled at mode set */
+
+ int dx, dy, dir=0, v1, v2, err, inc, dec;
+
+ /* [OK] I'm not quite sure yet how to do fractional coordinates */
+ /* [OK] just round them to integers for now */
+ x1 = (x1+0x8000) >> 16;
+ y1 = (y1+0x8000) >> 16;
+ x2 = (x2+0x8000) >> 16;
+ y2 = (y2+0x8000) >> 16;
+
+ /* [OK] calculate Bresenham parameters */
+ if (x1 < x2) {
+ dx = x2 - x1; dir |= 1;
+ } else
+ dx = x1 - x2;
+
+ if (y1 < y2) {
+ dy = y2 - y1; dir |= 2;
+ } else
+ dy = y1 - y2;
+
+ if (dx < dy) {
+ v1 = dx; v2 = dy; dir |= 4;
+ } else {
+ v1 = dy; v2 = dx;
+ }
+
+ inc = 2*v1;
+ err = inc - v2;
+ /* [OK] I don't know what this 0x3FFFF is for, it was just part
+ of the mach64 source code I had access to... */
+ dec = 0x3FFFF - 2*(v2-v1);
+
+ /* [OK] do the line */
+ WaitForFifo(af, 8);
+ mm_port(mmDPFGCOL) = color;
+ mm_port(mmDX) = x1;
+ mm_port(mmDY) = y1 + af_active_page*af_height;
+ mm_port(mmDCNTL) = (mach64_dcntl&(DC_LAST_P|DC_POLY)) | dir;
+ mm_port(mmDBRSERR) = err;
+ mm_port(mmDBRSINC) = inc;
+ mm_port(mmDBRSDEC) = dec;
+ mm_port(mmDBRSLEN) = (v2 + 1);
+
+ WaitForFifo(af, 1);
+ mm_port(mmDCNTL) = mach64_dcntl;
+}
+
diff --git a/mach64/drvhdr.c b/mach64/drvhdr.c
new file mode 100644
index 0000000..c22ac63
--- /dev/null
+++ b/mach64/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF ATI mach64 driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/mach64/notes.txt b/mach64/notes.txt
new file mode 100644
index 0000000..52b4e37
--- /dev/null
+++ b/mach64/notes.txt
@@ -0,0 +1,78 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ ATI mach64 driver implementation notes.
+
+
+
+ This driver is currently a limited implementation of VBE/AF for mach64.
+ It is not very well tested and may not work for you (if it doesn't,
+ give me your system description and a description of the problems).
+ It has a built-in table of known VESA modes, as well as all non-VESA
+ modes that the mach64 BIOS supports, but currently the non-VESA mode
+ setting doesn't work properly, so only VESA modes are enabled. However,
+ it is able to take advantage of extra VESA modes provided by tools like
+ Scitech Display Doctor.
+
+ It supports 8, 15, 16, 24, and 32 bits per pixel, if available. It
+ currently provides acceleration for these primitives:
+
+ DrawScan()
+ DrawPattScan()
+ DrawRect()
+ DrawPattRect()
+ BitBlt()
+ SrcTransBlt() (not in 24bpp)
+ DrawLine() (not in 24bpp)
+
+ These accelerated functions are planned and may be provided in the
+ future:
+
+ DrawTrap() (actually the mach64 seems to be able to draw entire
+ polygons, too bad there isn't a DrawPoly() in VBE/AF;
+ DrawTri() and DrawQuad() may be possible, but since
+ they are not widely used, who cares about them)
+ PutMonoImage() (using HOST transfer, perhaps)
+ BitBltSys() (using HOST transfer)
+ SrcTransBltSys() (same here)
+ SetCursor()
+ SetCursorPos()
+ SetCursorColor()
+ ShowCursor()
+
+ This driver is not portable to anything but DOS+DPMI, since it uses
+ DPMI to communicate with the mach64 BIOS.
+
+ Both linear and banked modes are supported, but SetBank32 is in the
+ current (sloppy) implementation not fully relocatable, but this should
+ rarely be a problem since linear modes are much more fun anyway.
+
+ If you want to have 32bpp and 1600x1200 modes without having to
+ install Scitech Display Doctor, define REFUSE_VESA and try to find out
+ why the mach64 mode settings doesn't work properly, then uncomment the
+ appropriate extra modes, and report to me.
+
+ Virtual heights above screen height (for hardware scrolling) may not
+ work properly above 8bpp, I'm not sure why yet, but it looks like it
+ could be a bug in Allegro.
+
+ DrawLine does not seem to be rounded exactly like Allegro's, which
+ becomes evident when clipping.
+
+ I'm not sure how to do patterns. It is possible to load an 8x8 mono
+ pattern into the mach64 registers and use it, but I'm not sure how,
+ but I made a guess and implemented that, and it seems to work, but
+ I'm not totally sure. As for color patterns, I have just disabled
+ them since I haven't figured out how to do those yet. It would be
+ possible to use Shawn's technique; to bitblt them from offscreen VRAM,
+ but use TILE_X enabled for automatic tiling, but it doesn't seem
+ worthwhile at present, if there is a better way.
+
+ Ove Kaaven
+
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..2cc1809
--- /dev/null
+++ b/makefile
@@ -0,0 +1,99 @@
+##############################################################################
+# #
+# FreeBE/AF makefile. #
+# #
+# The default target is 'drivers', which will build all the vbeaf.drv #
+# files. Run 'make cardname/vbeaf.drv' to compile a specific driver. #
+# #
+# To build the install program for a binary distribution, run 'make all'. #
+# This requires the Allegro utilties dat.exe and exedat.exe (from the #
+# allegro/tools/ directory) to be located somewhere on your path. #
+# #
+# To reconvert the documentation from the ._tx source, run "make docs". #
+# This needs the Allegro makedoc utility (allegro/obj/djgpp/makedoc.exe) #
+# to be located somewhere on your path. #
+# #
+# The 'clean' target requires the rm utility from GNU fileutils. #
+# #
+##############################################################################
+
+
+DRIVERS = stub ati avance cirrus54 mach64 matrox \
+ nvidia paradise s3 tgui trident tseng video7
+
+ifdef DEBUGMODE
+CFLAGS = -O -Wall -Werror
+else
+ifdef PGCC
+CFLAGS = -O6 -mpentium -fomit-frame-pointer -Wall -Werror
+else
+CFLAGS = -O3 -m486 -fomit-frame-pointer -Wall -Werror
+endif
+endif
+
+.PHONY: dummy drivers install all docs clean
+
+.PRECIOUS: %.o drvgen.exe
+
+drivers: $(addsuffix /vbeaf.drv, $(DRIVERS))
+
+install: install.exe
+
+all: drivers install
+
+ifdef DEBUGMODE
+
+install.exe: install.o drivers.dat
+ gcc -g -o install.exe install.o -lalleg
+ exedat -c -a install.exe drivers.dat
+
+else
+
+install.exe: install.o drivers.dat
+ gcc -s -o install.exe install.o -lalleg
+ -djp -q install.exe
+ exedat -c -a install.exe drivers.dat
+
+endif
+
+drivers.dat: $(addsuffix .dat, $(DRIVERS))
+ dat -a -s1 drivers.dat $(addsuffix .dat, $(DRIVERS))
+
+%.dat: %/vbeaf.drv %/notes.txt
+ dat -a -s1 $*.dat -t DATA $*/vbeaf.drv $*/notes.txt
+
+#special target needed to force recursive makes
+dummy:
+
+%/vbeaf.drv: start.o helper.o drvgen.o dummy
+ @cd $*
+ make.exe -f ../makefile IFLAGS=-I.. vbeaf.drv
+ @cd ..
+
+vbeaf.drv: drvgen.exe ../start.o ../helper.o $(subst drvhdr.o ,,$(subst .c,.o,$(wildcard *.c)))
+ drvgen vbeaf.drv OemExt PlugAndPlayInit StartDriver $(subst drvgen.exe ,,$^)
+
+drvgen.exe: ../drvgen.o drvhdr.o
+ gcc -s -o drvgen.exe ../drvgen.o drvhdr.o
+
+%.o: %.c
+ gcc $(CFLAGS) $(IFLAGS) -MMD -o $@ -c $<
+
+%.o: %.s
+ gcc -x assembler-with-cpp -o $@ -c $<
+
+docs: freebe.html freebe.txt readme.txt
+
+freebe.html: freebe._tx
+ makedoc -html freebe.html freebe._tx
+
+freebe.txt: freebe._tx
+ makedoc -ascii freebe.txt freebe._tx
+
+readme.txt: freebe._tx
+ makedoc -part -ascii readme.txt freebe._tx
+
+clean:
+ -rm -rv *.o */*.o *.d */*.d *.exe */*.exe *.dat */*.drv freebe.html freebe.txt readme.txt
+
+-include *.d
diff --git a/matrox/driver.c b/matrox/driver.c
new file mode 100644
index 0000000..b49c041
--- /dev/null
+++ b/matrox/driver.c
@@ -0,0 +1,2300 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * 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= 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>((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; iIOMemMaps[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; iIOMemMaps[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;
+ }
+}
+
diff --git a/matrox/drvhdr.c b/matrox/drvhdr.c
new file mode 100644
index 0000000..1afdcd4
--- /dev/null
+++ b/matrox/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF Matrox driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/matrox/notes.txt b/matrox/notes.txt
new file mode 100644
index 0000000..eca7805
--- /dev/null
+++ b/matrox/notes.txt
@@ -0,0 +1,55 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ Matrox driver implementation notes.
+
+
+
+ This driver supports the Millenium, Mystique, and Millenium II (both PCI
+ and AGP) cards.
+
+ It supports color depths of 8, 15, 16, and 32 bits per pixel in both
+ linear and banked modes, and should be able to use all the resolutions
+ provided by your underlying VESA driver. It provides accelerated versions
+ of the VBE/AF functions:
+
+ DrawScan()
+ DrawPattScan()
+ DrawColorPattScan()
+ DrawRect()
+ DrawPattRect()
+ DrawColorPattRect()
+ DrawLine()
+ DrawTrap()
+ PutMonoImage()
+ BitBlt()
+ BitBltSys()
+ SrcTransBlt() - Mystique only
+ SrcTransBltSys() - Mystique only
+
+ This driver supports the FreeBE/AF extension mechanism for enabling true
+ protected mode access to video memory. Uncomment the definition of
+ NO_HWPTR at the top of driver.c if you want to return to the standard
+ nearptr memory access.
+
+ Masked blitting from system memory is only enabled in 256 color modes,
+ because in truecolor resolutions it is actually faster to do the masking
+ checks in software (the increased pixel size means that too much time is
+ wasted copying zeros to the card, so it is more efficient for the cpu to
+ test and discard these).
+
+ Hardware cursors are supported, but only on the Mystique. The Millenium
+ does them quite differently, and I have no way to test any code for it.
+
+ This code is not portable to any platforms other than DOS+DPMI, because
+ it uses VESA calls to set the initial video mode.
+
+
+ By Shawn Hargreaves
+ shawn@talula.demon.co.uk
diff --git a/nvidia/driver.c b/nvidia/driver.c
new file mode 100644
index 0000000..1fc0f7f
--- /dev/null
+++ b/nvidia/driver.c
@@ -0,0 +1,1607 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Accelerated driver for Riva 128 and TNT cards, by Shawn Hargreaves.
+ *
+ * The VGA mode setting routines are based on the TGUI driver by
+ * Salvador Eduardo Tropea.
+ *
+ * This file provides a VBE/AF interface to the hardware routines
+ * in riva_hw.c, which was lifted directly from XFree86, and is
+ * copyrighted by NVidia under a BSD-style license. See the comment
+ * at the top of riva_hw.c for details. Much kudos to NVidia for
+ * supplying such a useful file.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include
+
+#include "vbeaf.h"
+#include "riva_hw.h"
+#include "font.h"
+
+
+
+/* remove this define for a completely native, register level mode set */
+// #define USE_VESA
+
+
+
+/* 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 DrawScan(AF_DRIVER *af, long color, long y, long x1, long x2);
+void DrawRect(AF_DRIVER *af, unsigned long color, long left, long top, long width, long height);
+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);
+
+
+/* hardware info structure as defined by the NVidia libs */
+RIVA_HW_INST riva;
+
+RIVA_HW_STATE state;
+
+RIVA_HW_STATE orig_state;
+
+
+/* VGA register information */
+typedef struct VGA_REGS
+{
+ unsigned char crt[25];
+ unsigned char att[21];
+ unsigned char gra[9];
+ unsigned char seq[5];
+ unsigned char mor;
+} VGA_REGS;
+
+
+VGA_REGS orig_regs;
+
+
+unsigned short ports_table[] =
+{
+ 0x3B0, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7,
+ 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF,
+ 0x3C0, 0x3C1, 0x3C2, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7,
+ 0x3C8, 0x3C9, 0x3CA, 0x3CB, 0x3CC, 0x3CD, 0x3CE, 0x3CF,
+ 0x3D0, 0x3D1, 0x3D2, 0x3D3, 0x3D4, 0x3D5, 0x3D6, 0x3D7,
+ 0x3D8, 0x3D9, 0x3DA, 0x3DB, 0x3DC, 0x3DD, 0x3DE, 0x3DF,
+ 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 | fafDrawRect | fafDrawTrap | fafPutMonoImage | fafBitBlt)
+ },
+
+ { 0, 0 }
+};
+
+#define CFG_FEATURES config_data[0].value
+
+
+/* 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;
+
+AF_PALETTE af_palette[256];
+
+AF_CURSOR the_cursor;
+
+int cur_color;
+
+int cursor_fg;
+int cursor_bg;
+
+int cur_doublemode;
+
+int riva_mix_mode;
+int riva_current_mix;
+
+
+/* magic numbers (for my driver, not hardware) */
+#define RIVA128 128
+#define TNT 42
+
+
+/* PCI device identifiers */
+#define PCI_VENDOR_NVIDIA_SGS 0x12D2
+#define PCI_VENDOR_NVIDIA 0x10DE
+
+#define PCI_CHIP_RIVA128 0x0018
+#define PCI_CHIP_RIVA128_2 0x001C
+
+#define PCI_CHIP_TNT 0x0020
+#define PCI_CHIP_TNT_2 0x0024
+
+
+int nvidia_list[] = {
+ PCI_VENDOR_NVIDIA_SGS, PCI_CHIP_RIVA128, RIVA128,
+ PCI_VENDOR_NVIDIA_SGS, PCI_CHIP_RIVA128_2, RIVA128,
+ PCI_VENDOR_NVIDIA, PCI_CHIP_TNT, TNT,
+ PCI_VENDOR_NVIDIA, PCI_CHIP_TNT_2, TNT,
+ 0
+};
+
+
+int nvidia_id;
+
+
+/* list of supported video modes */
+typedef struct VIDEO_MODE
+{
+ int vesa;
+ int bpp;
+ int w;
+ int h;
+ int nv_screen, nv_horiz, nv_arb0, nv_arb1, nv_vpll;
+ VGA_REGS vga;
+} VIDEO_MODE;
+
+
+#define NUM_MODES 23
+
+
+VIDEO_MODE mode_list[NUM_MODES] =
+{
+ { 0x130, 8, 320, 200, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 192, 0, 0, 0, 0, 0, 0, 156, 14, 143, 40, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x134, 8, 320, 240, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 11, 62, 0, 192, 0, 0, 0, 0, 0, 0, 234, 12, 223, 40, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 227 } },
+ { 0x131, 8, 320, 400, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 40, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x100, 8, 640, 400, 0, 0, 3, 16, 247054, { { 95, 79, 79, 131, 83, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 80, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x101, 8, 640, 480, 0, 0, 131, 16, 247054, { { 95, 79, 79, 131, 83, 159, 11, 62, 0, 64, 0, 0, 0, 0, 0, 0, 234, 12, 223, 80, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } },
+ { 0x103, 8, 800, 600, 0, 0, 3, 16, 162571, { { 127, 99, 99, 131, 106, 26, 114, 240, 0, 96, 0, 0, 0, 0, 0, 0, 89, 13, 87, 100, 0, 87, 115, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 43 } },
+ { 0x105, 8, 1024, 768, 0, 0, 3, 16, 95757, { { 163, 127, 127, 135, 132, 149, 36, 245, 0, 96, 0, 0, 0, 0, 0, 0, 3, 9, 255, 128, 0, 255, 37, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } },
+ { 0x107, 8, 1280, 1024, 21, 0, 3, 16, 115981, { { 207, 159, 159, 147, 169, 25, 40, 90, 0, 96, 0, 0, 0, 0, 0, 0, 1, 4, 255, 160, 0, 255, 41, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 43 } },
+ { 0x10E, 16, 320, 200, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 192, 0, 0, 0, 0, 0, 0, 156, 14, 143, 80, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x135, 16, 320, 240, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 11, 62, 0, 192, 0, 0, 0, 0, 0, 0, 234, 12, 223, 80, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 227 } },
+ { 0x132, 16, 320, 400, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 80, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x13D, 16, 640, 400, 0, 0, 3, 16, 247054, { { 95, 79, 79, 131, 83, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 160, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x111, 16, 640, 480, 0, 0, 131, 16, 247054, { { 95, 79, 79, 131, 83, 159, 11, 62, 0, 64, 0, 0, 0, 0, 0, 0, 234, 12, 223, 160, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } },
+ { 0x114, 16, 800, 600, 0, 0, 3, 16, 162571, { { 127, 99, 99, 131, 106, 26, 114, 240, 0, 96, 0, 0, 0, 0, 0, 0, 89, 13, 87, 200, 0, 87, 115, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 43 } },
+ { 0x117, 16, 1024, 768, 0, 0, 3, 16, 95757, { { 163, 127, 127, 135, 132, 149, 36, 245, 0, 96, 0, 0, 0, 0, 0, 0, 3, 9, 255, 0, 0, 255, 37, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } },
+ { 0x11A, 16, 1280, 1024, 21, 0, 3, 16, 115981, { { 207, 159, 159, 147, 169, 25, 40, 90, 0, 96, 0, 0, 0, 0, 0, 0, 1, 4, 255, 64, 0, 255, 41, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 43 } },
+ { 0x10F, 32, 320, 200, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 192, 0, 0, 0, 0, 0, 0, 156, 14, 143, 160, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x136, 32, 320, 240, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 11, 62, 0, 192, 0, 0, 0, 0, 0, 0, 234, 12, 223, 160, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 227 } },
+ { 0x133, 32, 320, 400, 0, 0, 3, 16, 312590, { { 45, 39, 39, 145, 42, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 160, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x13E, 32, 640, 400, 0, 0, 3, 16, 247054, { { 95, 79, 79, 131, 83, 159, 191, 31, 0, 64, 0, 0, 0, 0, 0, 0, 156, 14, 143, 64, 0, 143, 192, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 99 } },
+ { 0x112, 32, 640, 480, 0, 0, 131, 16, 247054, { { 95, 79, 79, 131, 83, 159, 11, 62, 0, 64, 0, 0, 0, 0, 0, 0, 234, 12, 223, 64, 0, 223, 12, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } },
+ { 0x115, 32, 800, 600, 0, 0, 3, 16, 162571, { { 127, 99, 99, 131, 106, 26, 114, 240, 0, 96, 0, 0, 0, 0, 0, 0, 89, 13, 87, 144, 0, 87, 115, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 43 } },
+ { 0x118, 32, 1024, 768, 0, 0, 3, 17, 95757, { { 163, 127, 127, 135, 132, 149, 36, 245, 0, 96, 0, 0, 0, 0, 0, 0, 3, 9, 255, 0, 0, 255, 37, 227, 255 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 65, 0, 15, 0, 0 }, { 0, 0, 0, 0, 0, 64, 5, 15, 255 }, { 3, 1, 15, 0, 14 }, 235 } }
+};
+
+
+short available_modes[NUM_MODES+1] =
+{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, -1
+};
+
+
+
+
+/* read_crt:
+ * Reads a VGA register.
+ */
+int read_crt(int index)
+{
+ outportb(0x3D4, index);
+ return inportb(0x3D5);
+}
+
+
+
+/* read_gra:
+ * Reads a VGA register.
+ */
+int read_gra(int index)
+{
+ outportb(0x3CE, index);
+ return inportb(0x3CF);
+}
+
+
+
+/* read_seq:
+ * Reads a VGA register.
+ */
+int read_seq(int index)
+{
+ outportb(0x3C4, index);
+ return inportb(0x3C5);
+}
+
+
+
+/* write_crt:
+ * Writes a VGA register.
+ */
+void write_crt(int index, int value)
+{
+ outportb(0x3D4,index);
+ outportb(0x3D5, value);
+}
+
+
+
+/* write_gra:
+ * Writes a VGA register.
+ */
+void write_gra(int index, int value)
+{
+ outportb(0x3CE, index);
+ outportb(0x3CF, value);
+}
+
+
+
+/* write_seq:
+ * Writes a VGA register.
+ */
+void write_seq(int index, int value)
+{
+ outportb(0x3C4, index);
+ outportb(0x3C5, value);
+}
+
+
+
+/* read_att:
+ * Reads a VGA register.
+ */
+int read_att(int index)
+{
+ inportb(0x3DA);
+ outportb(0x3C0, index);
+ return inportb(0x3C1);
+}
+
+
+
+/* att_end_reads:
+ * Finishes a VGA register read.
+ */
+void att_end_reads()
+{
+ inportb(0x3DA);
+ outportb(0x3C0, 0x20);
+}
+
+
+
+/* write_att:
+ * Writes a VGA register.
+ */
+void write_att(int index, int val)
+{
+ outportb(0x3C0, index);
+ outportb(0x3C0, val);
+}
+
+
+
+/* read_mor:
+ * Reads a VGA register.
+ */
+int read_mor()
+{
+ return inportb(0x3CC);
+}
+
+
+
+/* write_mor:
+ * Writes a VGA register.
+ */
+void write_mor(int val)
+{
+ outportb(0x3C2, val);
+}
+
+
+
+/* unload_vga_regs:
+ * Saves a VGA register set into a structure.
+ */
+void unload_vga_regs(VGA_REGS *regs)
+{
+ int i, mor_val;
+
+ mor_val = read_mor();
+ write_mor(mor_val | 1);
+ regs->mor = mor_val;
+
+ for (i=0; i<25; i++)
+ regs->crt[i] = read_crt(i);
+
+ for (i=0; i<21; i++)
+ regs->att[i] = read_att(i);
+
+ att_end_reads();
+
+ for (i=0; i<9; i++)
+ regs->gra[i] = read_gra(i);
+
+ for (i=0; i<5; i++)
+ regs->seq[i] = read_seq(i);
+
+ write_mor(mor_val);
+}
+
+
+
+/* load_vga_regs:
+ * Loads a VGA register set from a structure.
+ */
+void load_vga_regs(VGA_REGS *regs)
+{
+ int i, crt11, mor_val;
+
+ mor_val = read_mor();
+ write_mor(mor_val | 1);
+
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+
+ write_seq(0x01, regs->seq[1] | 0x20);
+
+ write_seq(0x00, 1);
+
+ for (i=2; i<5; i++)
+ write_seq(i, regs->seq[i]);
+
+ write_seq(0x00, regs->seq[0]);
+
+ crt11 = regs->crt[0x11];
+ write_crt(0x11, crt11 & 0x7F);
+
+ for (i=0; i<25; i++)
+ if (i != 0x11)
+ write_crt(i, regs->crt[i]);
+
+ write_crt(0x11, crt11);
+
+ for (i=0; i<9; i++)
+ write_gra(i, regs->gra[i]);
+
+ inportb(0x3DA);
+
+ for (; i<21; i++)
+ write_att(i, regs->att[i]);
+
+ att_end_reads();
+
+ write_mor(regs->mor);
+
+ write_seq(0x01, regs->seq[1]);
+}
+
+
+
+/* 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 regBase, frameBase;
+ int bus_id;
+ char *name;
+ int i;
+
+ /* find PCI device */
+ nvidia_id = 0;
+ bus_id = 0;
+
+ for (i=0; nvidia_list[i]; i+=3) {
+ if (FindPCIDevice(nvidia_list[i+1], nvidia_list[i], 0, &bus_id)) {
+ nvidia_id = nvidia_list[i+2];
+ break;
+ }
+ }
+
+ if (!nvidia_id)
+ return -1;
+
+ /* set up driver information */
+ af->AvailableModes = available_modes;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveAccel2D);
+
+ if (CFG_FEATURES & fafLinear)
+ af->Attributes |= afHaveLinearBuffer;
+
+ if (CFG_FEATURES & fafBanked)
+ af->Attributes |= afHaveBankedBuffer;
+
+ if (CFG_FEATURES & fafHWCursor)
+ af->Attributes |= afHaveHWCursor;
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ /* work out the linear framebuffer and MMIO addresses */
+ regBase = PCIReadLong(bus_id, 16) & 0xFF800000;
+ frameBase = PCIReadLong(bus_id, 20) & 0xFF800000;
+
+ /* don't know the memory size yet, so guess 16 meg (this is yuck) */
+ af->LinearBasePtr = frameBase;
+ af->LinearSize = 16384;
+
+ af->IOMemoryBase[0] = regBase;
+ af->IOMemoryLen[0] = 16384*1024;
+
+ /* get access to the textmode font memory */
+ af->IOMemoryBase[1] = 0xB8000;
+ af->IOMemoryLen[1] = 32768;
+
+ /* set up the driver name */
+ if (nvidia_id == RIVA128)
+ name = "Riva 128";
+ else if (nvidia_id == TNT)
+ name = "Riva TNT";
+ else
+ return -1;
+
+ 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->SetCursor = SetCursor;
+ af->SetCursorPos = SetCursorPos;
+ af->SetCursorColor = SetCursorColor;
+ af->ShowCursor = ShowCursor;
+ af->WaitTillIdle = WaitTillIdle;
+ af->SetMix = SetMix;
+ af->DrawScan = DrawScan;
+ af->DrawRect = DrawRect;
+ af->DrawTrap = DrawTrap;
+ af->PutMonoImage = PutMonoImage;
+ af->BitBlt = BitBlt;
+
+ 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)
+{
+ int tmp;
+
+ riva.EnableIRQ = 0;
+
+ riva.IO = (inportb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
+
+ riva.PRAMDAC = (unsigned *)(af->IOMemMaps[0]+0x00680000);
+ riva.PFB = (unsigned *)(af->IOMemMaps[0]+0x00100000);
+ riva.PFIFO = (unsigned *)(af->IOMemMaps[0]+0x00002000);
+ riva.PGRAPH = (unsigned *)(af->IOMemMaps[0]+0x00400000);
+ riva.PEXTDEV = (unsigned *)(af->IOMemMaps[0]+0x00101000);
+ riva.PTIMER = (unsigned *)(af->IOMemMaps[0]+0x00009000);
+ riva.PMC = (unsigned *)(af->IOMemMaps[0]+0x00000000);
+ riva.FIFO = (unsigned *)(af->IOMemMaps[0]+0x00800000);
+
+ if (nvidia_id == RIVA128) {
+ riva.Architecture = 3;
+ riva.PRAMIN = (unsigned *)(af->LinearMem+0x00C00000);
+ }
+ else if (nvidia_id == TNT) {
+ riva.Architecture = 4;
+ riva.PRAMIN = (unsigned *)(af->IOMemMaps[0]+0x00710000);
+ riva.PCRTC = (unsigned *)(af->IOMemMaps[0]+0x00600000);
+ }
+ else
+ return -1;
+
+ RivaGetConfig(&riva);
+
+ /* unlock registers */
+ outportb(riva.IO+4, 0x11);
+ tmp = inportb(riva.IO+5);
+ outportb(riva.IO+5, tmp & 0x7F);
+ outportb(riva.LockUnlockIO, riva.LockUnlockIndex);
+ outportb(riva.LockUnlockIO+1, 0x57);
+
+ unload_vga_regs(&orig_regs);
+ riva.UnloadStateExt(&riva, &orig_state);
+
+ af->TotalMemory = MIN(riva.RamAmountKBytes, 16384);
+
+ return 0;
+}
+
+
+
+/* FreeBEX:
+ * Returns an interface structure for the requested FreeBE/AF extension.
+ */
+void *FreeBEX(AF_DRIVER *af, unsigned long id)
+{
+ switch (id) {
+
+ 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 |
+ afHaveAccel2D);
+
+ if (CFG_FEATURES & fafLinear)
+ modeInfo->Attributes |= afHaveLinearBuffer;
+
+ if (CFG_FEATURES & fafBanked)
+ modeInfo->Attributes |= afHaveBankedBuffer;
+
+ if (CFG_FEATURES & fafHWCursor)
+ modeInfo->Attributes |= afHaveHWCursor;
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ /* available pages of video memory */
+ modeInfo->MaxBuffers = (af->TotalMemory * 1024) /
+ (info->w * info->h * BYTES_PER_PIXEL(info->bpp));
+
+ modeInfo->BnkMaxBuffers = modeInfo->LinMaxBuffers = modeInfo->MaxBuffers;
+
+ /* scanline length info */
+ modeInfo->BytesPerScanLine = info->w * BYTES_PER_PIXEL(info->bpp);
+ modeInfo->LinBytesPerScanLine = info->w * BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxBytesPerScanLine = 2048 * BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+
+ /* pixel format */
+ switch (info->bpp) {
+
+ case 32:
+ case 24:
+ modeInfo->RedMaskSize = modeInfo->LinRedMaskSize = 8;
+ modeInfo->RedFieldPosition = modeInfo->LinRedFieldPosition = 16;
+ modeInfo->GreenMaskSize = modeInfo->LinGreenMaskSize = 8;
+ modeInfo->GreenFieldPosition = modeInfo->LinGreenFieldPosition = 8;
+ modeInfo->BlueMaskSize = modeInfo->LinBlueMaskSize = 8;
+ modeInfo->BlueFieldPosition = modeInfo->LinBlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = modeInfo->LinRsvdMaskSize = 8;
+ modeInfo->RsvdFieldPosition = modeInfo->LinRsvdFieldPosition = 24;
+ break;
+
+ case 16:
+ modeInfo->RedMaskSize = modeInfo->LinRedMaskSize = 5;
+ modeInfo->RedFieldPosition = modeInfo->LinRedFieldPosition = 11;
+ modeInfo->GreenMaskSize = modeInfo->LinGreenMaskSize = 6;
+ modeInfo->GreenFieldPosition = modeInfo->LinGreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = modeInfo->LinBlueMaskSize = 5;
+ modeInfo->BlueFieldPosition = modeInfo->LinBlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = modeInfo->LinRsvdMaskSize = 0;
+ modeInfo->RsvdFieldPosition = modeInfo->LinRsvdFieldPosition = 0;
+ break;
+
+ case 15:
+ modeInfo->RedMaskSize = modeInfo->LinRedMaskSize = 5;
+ modeInfo->RedFieldPosition = modeInfo->LinRedFieldPosition = 10;
+ modeInfo->GreenMaskSize = modeInfo->LinGreenMaskSize = 6;
+ modeInfo->GreenFieldPosition = modeInfo->LinGreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = modeInfo->LinBlueMaskSize = 5;
+ modeInfo->BlueFieldPosition = modeInfo->LinBlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = modeInfo->LinRsvdMaskSize = 1;
+ modeInfo->RsvdFieldPosition = modeInfo->LinRsvdFieldPosition = 15;
+ break;
+
+ default:
+ modeInfo->RedMaskSize = modeInfo->LinRedMaskSize = 0;
+ modeInfo->RedFieldPosition = modeInfo->LinRedFieldPosition = 0;
+ modeInfo->GreenMaskSize = modeInfo->LinGreenMaskSize = 0;
+ modeInfo->GreenFieldPosition = modeInfo->LinGreenFieldPosition = 0;
+ modeInfo->BlueMaskSize = modeInfo->LinBlueMaskSize = 0;
+ modeInfo->BlueFieldPosition = modeInfo->LinBlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = modeInfo->LinRsvdMaskSize = 0;
+ modeInfo->RsvdFieldPosition = modeInfo->LinRsvdFieldPosition = 0;
+ break;
+ }
+
+ /* 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)
+{
+ int linear = ((mode & 0x4000) != 0);
+ int noclear = ((mode & 0x8000) != 0);
+ long available_vram;
+ long used_vram;
+ VIDEO_MODE *info;
+ int i;
+
+ #ifdef USE_VESA
+ RM_REGS r;
+ #endif
+
+ /* 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];
+
+ /* adjust the virtual width */
+ *bytesPerLine = ((MAX(info->w, virtualX) + 15) & ~15) * BYTES_PER_PIXEL(info->bpp);
+
+ /* calculate NVidia register state (we only sort of half-use this
+ * data, because I'm too dumb to figure out how to do it properly :-)
+ */
+ riva.CalcStateExt(&riva, &state,
+ info->bpp, /* bpp */
+ *bytesPerLine/BYTES_PER_PIXEL(info->bpp), /* w */
+ info->w, /* hsize */
+ 0, /* hdisplay */
+ 0, /* hstart */
+ 0, /* hend */
+ 0, /* htotal */
+ info->h, /* height */
+ 0, /* vdisplay */
+ 0, /* vstart */
+ 0, /* vend */
+ 0, /* vtotal */
+ 0 /* clock */
+ );
+
+ #ifdef USE_VESA
+
+ /* call VESA to set the mode */
+ r.x.ax = 0x4F02;
+ r.x.bx = info->vesa;
+ if (linear)
+ r.x.bx |= 0x4000;
+ if (noclear)
+ r.x.bx |= 0x8000;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+
+ /* debugging code: dump register values to stdout */
+ /*
+ {
+ RIVA_HW_STATE cur_state;
+ VGA_REGS cur_regs;
+
+ unload_vga_regs(&cur_regs);
+ riva.UnloadStateExt(&riva, &cur_state);
+
+ trace_printf("%dx%d, %d\n", info->w, info->h, info->bpp);
+ trace_printf("%d\n", cur_state.screen);
+ trace_printf("%d\n", cur_state.horiz);
+ trace_printf("%d\n", cur_state.arbitration0);
+ trace_printf("%d\n", cur_state.arbitration1);
+ trace_printf("%d\n", cur_state.vpll);
+
+ trace_printf("{ ");
+ for (i=0; i<25; i++) trace_printf("%d, ", cur_regs.crt[i]);
+ trace_printf("}\n");
+
+ trace_printf("{ ");
+ for (i=0; i<21; i++) trace_printf("%d, ", cur_regs.att[i]);
+ trace_printf("}\n");
+
+ trace_printf("{ ");
+ for (i=0; i<9; i++) trace_printf("%d, ", cur_regs.gra[i]);
+ trace_printf("}\n");
+
+ trace_printf("{ ");
+ for (i=0; i<5; i++) trace_printf("%d, ", cur_regs.seq[i]);
+ trace_printf("}\n");
+
+ trace_printf("%d\n\n", cur_regs.mor);
+ }
+ */
+
+ riva.LoadStateExt(&riva, &state, FALSE);
+
+ #else
+
+ /* do a true register level mode set */
+ state.screen = info->nv_screen;
+ state.horiz = info->nv_horiz;
+ state.arbitration0 = info->nv_arb0;
+ state.arbitration1 = info->nv_arb1;
+ state.vpll = info->nv_vpll;
+
+ load_vga_regs(&info->vga);
+ riva.LoadStateExt(&riva, &state, TRUE);
+
+ if (info->bpp == 8) {
+ for (i=0; i<256; i++) {
+ outportb(0x3C8, i);
+ outportb(0x3C9, DefaultVGAPalette[i*3]);
+ outportb(0x3C9, DefaultVGAPalette[i*3+1]);
+ outportb(0x3C9, DefaultVGAPalette[i*3+2]);
+ }
+ }
+
+ #endif
+
+ /* set the virtual width */
+ outportb(0x3D4, 0x13);
+ outportb(0x3D5, *bytesPerLine/8);
+
+ /* 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;
+
+ 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;
+ }
+
+ /* set up the accelerator engine */
+ RIVA_FIFO_FREE(riva, Rop, 1);
+ riva.Rop->Rop3 = 0xCC;
+
+ RIVA_FIFO_FREE(riva, Clip, 2);
+ riva.Clip->TopLeft = 0;
+ riva.Clip->WidthHeight = 0x40004000;
+
+ RIVA_FIFO_FREE(riva, Patt, 5);
+ riva.Patt->Shape = 0;
+ riva.Patt->Color0 = ~0;
+ riva.Patt->Color1 = ~0;
+ riva.Patt->Monochrome[0] = 0;
+ riva.Patt->Monochrome[1] = 0;
+
+ SetMix(af, AF_REPLACE_MIX, AF_FORE_MIX);
+
+ riva_current_mix = 0;
+
+ cur_color = -1;
+ cur_doublemode = (info->h < 400);
+
+ #ifndef USE_VESA
+
+ /* clear the framebuffer */
+ if (!noclear) {
+ DrawRect(af, 0, 0, 0, af_width_pixels, af_height);
+ WaitTillIdle(af);
+ }
+
+ #endif
+
+ return 0;
+}
+
+
+
+/* RestoreTextMode:
+ * Returns to text mode, shutting down the accelerator hardware.
+ */
+void RestoreTextMode(AF_DRIVER *af)
+{
+ unsigned *p = (unsigned *)VGA8x16Font;
+ unsigned *font = af->IOMemMaps[1];
+ int i, j;
+
+ /* shut down video mode */
+ riva.LoadStateExt(&riva, &orig_state, TRUE);
+ load_vga_regs(&orig_regs);
+
+ /* reset the accelerator */
+ RIVA_FIFO_FREE(riva, Rop, 1);
+ riva.Rop->Rop3 = 0xCC;
+
+ RIVA_FIFO_FREE(riva, Clip, 2);
+ riva.Clip->TopLeft = 0;
+ riva.Clip->WidthHeight = 0x40004000;
+
+ RIVA_FIFO_FREE(riva, Patt, 5);
+ riva.Patt->Shape = 0;
+ riva.Patt->Color0 = ~0;
+ riva.Patt->Color1 = ~0;
+ riva.Patt->Monochrome[0] = 0;
+ riva.Patt->Monochrome[1] = 0;
+
+ /* restore text mode font */
+ write_seq(4, 6);
+ write_seq(2, 4);
+ write_gra(5, 0);
+
+ for (i=0, j=0; i<1024; i+=4, j+=8) {
+ font[j+0] = p[i+0];
+ font[j+1] = p[i+1];
+ font[j+2] = p[i+2];
+ font[j+3] = p[i+3];
+ font[j+4] = 0;
+ font[j+5] = 0;
+ font[j+6] = 0;
+ font[j+7] = 0;
+ }
+
+ /* clear text mode screen */
+ write_seq(4, 2);
+ write_seq(2, 3);
+ write_gra(5, 0x10);
+
+ for (i=0; i<1000; i++)
+ font[i] = 0x07200720;
+
+ /* restore text mode palette */
+ for (i=0; i<256; i++) {
+ outportb(0x3C8, i);
+ outportb(0x3C9, DefaultTXTPalette[i*3]);
+ outportb(0x3C9, DefaultTXTPalette[i*3+1]);
+ outportb(0x3C9, DefaultTXTPalette[i*3+2]);
+ }
+}
+
+
+
+/* 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;
+
+ if (waitVRT >= 0) {
+ addr = (((y + af_visible_page*af_height) * af_width_bytes) +
+ (x*BYTES_PER_PIXEL(af_bpp)));
+
+ riva.SetStartAddress(&riva, addr);
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+ }
+
+ 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->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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i= 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 %ebx
+ pushl %edx
+
+ movl %edx, %ebx
+ shll $1, %ebx
+
+ movw $0x3D4, %dx
+ movw $0x571F, %ax
+ outw %ax, %dx
+ movb %bl, %ah
+ movb $0x1D, %al
+ outw %ax, %dx
+ movb $0x1E, %al
+ outw %ax, %dx
+
+ orb %bh, %bh
+ jz SkipHighBits
+
+ movb %bh, %ah
+ movb $0x29, %al
+ orb $3, %ah
+ outw %ax, %dx
+
+ SkipHighBits:
+ popl %edx
+ popl %ebx
+ 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)
+ );
+}
+
+
+
+/* pack RGB values into 5551 format */
+#define CURSOR_RGB(r, g, b) ((((r) >> 3) & 0x1F) << 10) | \
+ ((((g) >> 3) & 0x1F) << 5) | \
+ (((b) >> 3) & 0x1F) | 0x8000
+
+
+
+/* LoadCursor:
+ * Worker function for downloading a cursor image to the card.
+ */
+void LoadCursor()
+{
+ unsigned short image[32][32];
+ int i, j, x, y, save;
+
+ for (y=0; y<32; y++) {
+ for (x=0; x<32; x++) {
+ i = 1 << ((x/8)*8 + 7-(x&7));
+ j = (cur_doublemode) ? y/2 : y;
+
+ if (the_cursor.andMask[j] & i) {
+ if (the_cursor.xorMask[j] & i)
+ image[y][x] = cursor_fg;
+ else
+ image[y][x] = cursor_bg;
+ }
+ else
+ image[y][x] = 0;
+ }
+ }
+
+ save = riva.ShowHideCursor(&riva, 0);
+
+ for (i=0; iRop3 = riva_mix_mode;
+ riva_current_mix = riva_mix_mode;
+ }
+}
+
+
+
+/* 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)
+{
+ UpdateMix();
+
+ RIVA_FIFO_FREE(riva, Bitmap, 3);
+
+ riva.Bitmap->Color1A = color;
+
+ if (x1 < x2) {
+ riva.Bitmap->UnclippedRectangle[0].TopLeft = (x1<<16) | (y+af_y);
+ riva.Bitmap->UnclippedRectangle[0].WidthHeight = ((x2-x1)<<16) | 1;
+ }
+ else if (x2 < x1) {
+ riva.Bitmap->UnclippedRectangle[0].TopLeft = (x2<<16) | (y+af_y);
+ riva.Bitmap->UnclippedRectangle[0].WidthHeight = ((x1-x2)<<16) | 1;
+ }
+}
+
+
+
+/* DrawRect:
+ * Draws a hardware accelerated rectangle.
+ */
+void DrawRect(AF_DRIVER *af, unsigned long color, long left, long top, long width, long height)
+{
+ UpdateMix();
+
+ RIVA_FIFO_FREE(riva, Bitmap, 3);
+
+ riva.Bitmap->Color1A = color;
+ riva.Bitmap->UnclippedRectangle[0].TopLeft = (left<<16) | (top+af_y);
+ riva.Bitmap->UnclippedRectangle[0].WidthHeight = (width<<16) | height;
+}
+
+
+
+/* DrawTrap:
+ * Draws a filled trapezoid, using the current foreground mix mode.
+ */
+void DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap)
+{
+ int ix1, ix2;
+
+ UpdateMix();
+
+ RIVA_FIFO_FREE(riva, Bitmap, 1);
+ riva.Bitmap->Color1A = color;
+
+ while (trap->count--) {
+ ix1 = (trap->x1+0x8000) >> 16;
+ ix2 = (trap->x2+0x8000) >> 16;
+
+ if (ix1 < ix2) {
+ RIVA_FIFO_FREE(riva, Bitmap, 2);
+ riva.Bitmap->UnclippedRectangle[0].TopLeft = (ix1<<16) | (trap->y+af_y);
+ riva.Bitmap->UnclippedRectangle[0].WidthHeight = ((ix2-ix1)<<16) | 1;
+ }
+ else if (ix2 < ix1) {
+ RIVA_FIFO_FREE(riva, Bitmap, 2);
+ riva.Bitmap->UnclippedRectangle[0].TopLeft = (ix2<<16) | (trap->y+af_y);
+ riva.Bitmap->UnclippedRectangle[0].WidthHeight = ((ix1-ix2)<<16) | 1;
+ }
+
+ trap->x1 += trap->slope1;
+ trap->x2 += trap->slope2;
+ trap->y++;
+ }
+}
+
+
+
+/* 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)
+{
+ int i, w, h;
+
+ UpdateMix();
+
+ image += srcY*byteWidth + srcX/8;
+ srcX &= 7;
+
+ if (af_back_mix == AF_NOP_MIX) {
+ /* masked drawing mode */
+ RIVA_FIFO_FREE(riva, Bitmap, 3);
+
+ riva.Bitmap->ClipD.TopLeft = ((dstY+af_y) << 16) | (dstX+srcX);
+ riva.Bitmap->ClipD.BottomRight = ((dstY+af_y+height) << 16) | (dstX+width);
+ riva.Bitmap->Color1D = foreColor;
+
+ RIVA_FIFO_FREE(riva, Bitmap, 3);
+
+ if (width <= 8) {
+ /* for masked characters up to 8 pixels wide */
+ h = (height+3)/4;
+
+ riva.Bitmap->WidthHeightInD = (h<<18) | 8;
+ riva.Bitmap->WidthHeightOutD = (height<<16) | width;
+ riva.Bitmap->PointD = ((dstY+af_y)<<16) | dstX;
+
+ while (h--) {
+ RIVA_FIFO_FREE(riva, Bitmap, 1);
+ riva.Bitmap->MonochromeData1D = (image[0]) |
+ (image[byteWidth] << 8) |
+ (image[byteWidth*2] << 16) |
+ (image[byteWidth*3] << 24);
+ image += byteWidth*4;
+ }
+ }
+ else if (width <= 16) {
+ /* for masked characters up to 16 pixels wide */
+ h = (height+1)/2;
+
+ riva.Bitmap->WidthHeightInD = (h<<17) | 16;
+ riva.Bitmap->WidthHeightOutD = (height<<16) | width;
+ riva.Bitmap->PointD = ((dstY+af_y)<<16) | dstX;
+
+ while (h--) {
+ RIVA_FIFO_FREE(riva, Bitmap, 1);
+ riva.Bitmap->MonochromeData1D = (image[0]) |
+ (image[byteWidth] << 16);
+ image += byteWidth*2;
+ }
+ }
+ else {
+ /* for masked characters more than 16 pixels wide */
+ w = (width+31)/32;
+
+ riva.Bitmap->WidthHeightInD = (height<<16) | (w<<5);
+ riva.Bitmap->WidthHeightOutD = (height<<16) | width;
+ riva.Bitmap->PointD = ((dstY+af_y)<<16) | dstX;
+
+ while (height--) {
+ for (i=0; iMonochromeData1D = image[i];
+ }
+ image += byteWidth;
+ }
+ }
+ }
+ else {
+ /* opaque drawing mode */
+ RIVA_FIFO_FREE(riva, Bitmap, 4);
+
+ riva.Bitmap->ClipE.TopLeft = ((dstY+af_y) << 16) | (dstX+srcX);
+ riva.Bitmap->ClipE.BottomRight = ((dstY+af_y+height) << 16) | (dstX+width);
+ riva.Bitmap->Color0E = backColor;
+ riva.Bitmap->Color1E = foreColor;
+
+ RIVA_FIFO_FREE(riva, Bitmap, 3);
+
+ if (width <= 8) {
+ /* for opaque characters up to 8 pixels wide */
+ h = (height+3)/4;
+
+ riva.Bitmap->WidthHeightInE = (h<<18) | 8;
+ riva.Bitmap->WidthHeightOutE = (height<<16) | width;
+ riva.Bitmap->PointE = ((dstY+af_y)<<16) | dstX;
+
+ while (h--) {
+ RIVA_FIFO_FREE(riva, Bitmap, 1);
+ riva.Bitmap->MonochromeData01E = (image[0]) |
+ (image[byteWidth] << 8) |
+ (image[byteWidth*2] << 16) |
+ (image[byteWidth*3] << 24);
+ image += byteWidth*4;
+ }
+ }
+ else if (width <= 16) {
+ /* for opaque characters up to 16 pixels wide */
+ h = (height+1)/2;
+
+ riva.Bitmap->WidthHeightInE = (h<<17) | 16;
+ riva.Bitmap->WidthHeightOutE = (height<<16) | width;
+ riva.Bitmap->PointE = ((dstY+af_y)<<16) | dstX;
+
+ while (h--) {
+ RIVA_FIFO_FREE(riva, Bitmap, 1);
+ riva.Bitmap->MonochromeData01E = (image[0]) |
+ (image[byteWidth] << 16);
+ image += byteWidth*2;
+ }
+ }
+ else {
+ /* for opaque characters more than 16 pixels wide */
+ w = (width+31)/32;
+
+ riva.Bitmap->WidthHeightInE = (height<<16) | (w<<5);
+ riva.Bitmap->WidthHeightOutE = (height<<16) | width;
+ riva.Bitmap->PointE = ((dstY+af_y)<<16) | dstX;
+
+ while (height--) {
+ for (i=0; iMonochromeData01E = image[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)
+{
+ UpdateMix();
+
+ RIVA_FIFO_FREE(riva, Blt, 3);
+
+ riva.Blt->TopLeftSrc = ((top+af_y)<<16) | left;
+ riva.Blt->TopLeftDst = ((dstTop+af_y)<<16) | dstLeft;
+ riva.Blt->WidthHeight = (height<<16) | width;
+}
+
diff --git a/nvidia/drvhdr.c b/nvidia/drvhdr.c
new file mode 100644
index 0000000..7ef6816
--- /dev/null
+++ b/nvidia/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF NVidia driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/nvidia/font.h b/nvidia/font.h
new file mode 100644
index 0000000..b3f0539
--- /dev/null
+++ b/nvidia/font.h
@@ -0,0 +1,371 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+ terms and conditions of the FreeBE/AF project. */
+
+/* Well, I guess the fonts are Copyrighted by Trident but if you use this
+ driver then you have a Trident card so I can't see any problem.
+ But don't use it for other driver without having clear if you can do it.
+*/
+
+/* note from Shawn: this font is identical to the one in my NVidia BIOS,
+ * so I guess the copyright isn't a problem. I'm just using your data to
+ * save me the bother of having to grab my own. */
+
+unsigned char VGA8x16Font[256*16]={
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x99,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
+0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
+0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
+0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x18,0x18,0xFF,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x0E,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0xE6,0x66,0x6C,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0xE7,0xFF,0xDB,0xDB,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x6C,0x6C,0x38,0x38,0x6C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFF,0xC3,0x83,0x06,0x0C,0x18,0x30,0x61,0xC3,0xFF,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x3E,0x00,0x00,0x00,0x00,
+0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
+0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0xDC,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xE6,0xFF,0xDB,0xDB,0xDB,0xDB,0xDB,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x62,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,
+0x00,0x00,0xCC,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xCC,0xCC,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0xC6,0xC6,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x1B,0x7E,0xD8,0xDC,0x77,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+0x00,0xC6,0xC6,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0xFC,0x66,0x66,0x7C,0x62,0x66,0x6F,0x66,0x66,0x66,0xF3,0x00,0x00,0x00,0x00,
+0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xCE,0x93,0x06,0x0C,0x1F,0x00,0x00,
+0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9A,0x3F,0x06,0x0F,0x00,0x00,
+0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x33,0x66,0xCC,0x66,0x33,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xCC,0x66,0x33,0x66,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,
+0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
+0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xDC,0xC6,0xC3,0xC3,0xC3,0xCE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x80,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x03,0x06,0x7E,0xCF,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0xFF,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0xFF,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
+0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x70,0x98,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+unsigned char DefaultTXTPalette[768]={
+0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
+0x00,0x2A,0x2A,0x2A,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x15,0x00,0x00,0x3F,0x00,0x2A,
+0x15,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x2A,0x2A,0x3F,
+0x00,0x15,0x00,0x00,0x15,0x2A,0x00,0x3F,0x00,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x2A,
+0x15,0x2A,0x2A,0x3F,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x15,0x00,0x15,0x3F,0x00,0x3F,
+0x15,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x2A,0x15,0x3F,0x2A,0x3F,0x15,0x2A,0x3F,0x3F,
+0x15,0x00,0x00,0x15,0x00,0x2A,0x15,0x2A,0x00,0x15,0x2A,0x2A,0x3F,0x00,0x00,0x3F,
+0x00,0x2A,0x3F,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x15,0x15,0x00,0x3F,0x15,0x2A,
+0x15,0x15,0x2A,0x3F,0x3F,0x00,0x15,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x3F,0x2A,0x3F,
+0x15,0x15,0x00,0x15,0x15,0x2A,0x15,0x3F,0x00,0x15,0x3F,0x2A,0x3F,0x15,0x00,0x3F,
+0x15,0x2A,0x3F,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
+0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
+0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
+0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
+0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
+0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
+0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
+0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
+0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
+0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
+0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
+0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
+0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
+0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
+0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
+0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
+0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
+0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
+0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
+0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
+0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
+0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
+0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
+0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
+0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
+0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
+0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
+0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
+0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
+0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
+0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
+0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
+0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
+0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
+0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
+0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
+0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
+0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};
+
+unsigned char DefaultVGAPalette[768]={
+0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
+0x00,0x2A,0x2A,0x15,0x00,0x2A,0x2A,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
+0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
+0x00,0x00,0x00,0x05,0x05,0x05,0x08,0x08,0x08,0x0B,0x0B,0x0B,0x0E,0x0E,0x0E,0x11,
+0x11,0x11,0x14,0x14,0x14,0x18,0x18,0x18,0x1C,0x1C,0x1C,0x20,0x20,0x20,0x24,0x24,
+0x24,0x28,0x28,0x28,0x2D,0x2D,0x2D,0x32,0x32,0x32,0x38,0x38,0x38,0x3F,0x3F,0x3F,
+0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x3F,0x3F,
+0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,
+0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,
+0x00,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,
+0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,
+0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,
+0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
+0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
+0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
+0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
+0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
+0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
+0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
+0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
+0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
+0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
+0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
+0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
+0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
+0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
+0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
+0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
+0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
+0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
+0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
+0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
+0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
+0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
+0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
+0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
+0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
+0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
+0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
+0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
+0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
+0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
+0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
+0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
+0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
+0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
+0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
+0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};
diff --git a/nvidia/notes.txt b/nvidia/notes.txt
new file mode 100644
index 0000000..ebc32b8
--- /dev/null
+++ b/nvidia/notes.txt
@@ -0,0 +1,90 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ NVidia driver implementation notes.
+
+
+
+ This driver should in theory support both the NVidia Riva 128 and Riva
+ TNT cards, but it has only been tested on the TNT. I'd be very interested
+ to hear whether it works on the 128 or not, although I'm afraid there
+ isn't much I can do to fix any problems on hardware that I don't own.
+
+ This driver doesn't work properly under Windows. It will run ok, but
+ after using it, you can't switch back to your Windows desktop. I have no
+ idea why this is.
+
+ It supports color depths of 8, 16, and 32 bits per pixel in both linear
+ and banked modes, and resolutions of 320x200, 320x240, 320x400, 640x400,
+ 640x480, 800x600, 1024x768, and 1280x1024 (this last not in 32 bit mode).
+ Other modes can easily be added if you know the register values for them.
+
+ It provides accelerated versions of the VBE/AF functions:
+
+ DrawScan()
+ DrawRect()
+ DrawTrap()
+ PutMonoImage()
+ BitBlt()
+ SetCursor()
+ SetCursorPos()
+ SetCursorColor()
+ ShowCursor()
+
+ Patterned drawing is not accelerated. I have some routines that sort-of
+ worked for this, but couldn't get them to do the right thing in all the
+ possible drawing modes. Since I got that code from an alpha version of an
+ XFree86 driver which itself doesn't do patterned modes properly, this is
+ not exactly surprising. I'll add that acceleration as soon as I get some
+ decent info about how it works.
+
+ This driver is unable to use more than 16 meg of video memory, because
+ I'm unable to detect the amount of vram until after I map the
+ framebuffer, at which point it is too late to request a larger memory
+ block.
+
+ The hardware scrolling and bank switching code may not be entirely
+ correct, because I didn't have any docs for how the bank switch system
+ works, and the scrolling routine supplied in XFree86 is broken. The code
+ in this driver works correctly on my TNT, but your mileage may vary.
+
+ This driver does not implement the FreeBE/AF farptr extension mechanism,
+ which means that it only works with nearptrs enabled. This could be
+ altered if enough people feel strongly about it, but would be a
+ considerable pain because I'd have to rewrite most of the NVidia helper
+ routines as well as my own driver code.
+
+ This code is heavily based on the NVidia driver from XFree86 version
+ 3.3.3.1. In particular, the source file riva_hw.c was copied directly
+ from XFree86. This imposes two restrictions on me. First, I have to say
+ that NVidia is an exceptionally cool company, and they deserve much
+ congratulation for releasing this nice bit of reusable driver source.
+ Also, to comply with their BSD-style licensing terms, I have to reproduce
+ this lovely little message:
+
+ Copyright 1993-1998 NVIDIA, Corporation. All rights reserved.
+
+ NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF
+ THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT
+ EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPORATION DISCLAIMS
+ ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED
+ WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A
+ PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORPORATION BE LIABLE
+ FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR
+ ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ SOURCE CODE.
+
+ Also thanks to Salvador Eduardo Tropea for the VGA mode setting routines
+ in his TGUI driver, which I shamelessly copied.
+
+
+ By Shawn Hargreaves
+ shawn@talula.demon.co.uk
diff --git a/nvidia/riva_hw.c b/nvidia/riva_hw.c
new file mode 100644
index 0000000..6023085
--- /dev/null
+++ b/nvidia/riva_hw.c
@@ -0,0 +1,1395 @@
+/*
+ * This file was taken from the XFree86 distribution.
+ * Minor modifications by Shawn Hargreaves are marked slh:
+ */
+
+ /***************************************************************************\
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
+|* international laws. Users and possessors of this source code are *|
+|* hereby granted a nonexclusive, royalty-free copyright license to *|
+|* use this code in individual and commercial software. *|
+|* *|
+|* Any use of this source code must include, in the user documenta- *|
+|* tion and internal comments to the code, notices to the end user *|
+|* as follows: *|
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
+|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
+|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
+|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
+|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
+|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
+|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
+|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
+|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
+|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
+|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
+|* *|
+|* U.S. Government End Users. This source code is a "commercial *|
+|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
+|* consisting of "commercial computer software" and "commercial *|
+|* computer software documentation," as such terms are used in *|
+|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
+|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
+|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
+|* all U.S. Government End Users acquire the source code with only *|
+|* those rights set forth herein. *|
+|* *|
+ \***************************************************************************/
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/riva_hw.c,v 1.1.2.3 1998/12/26 00:12:39 dawes Exp $ */
+
+#include
+
+#define inb inportb
+#define outb outportb
+
+
+#include "riva_hw.h"
+#include "riva_tbl.h"
+
+/*
+ * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT
+ * operate identically (except TNT has more memory and better 3D quality.
+ */
+
+static int nv3Busy
+(
+ RIVA_HW_INST *chip
+)
+{
+ return ((!(chip->PFIFO[0x00001214/4] & 0x10)) | (chip->PGRAPH[0x000006B0/4] & 0x01));
+}
+static int nv4Busy
+(
+ RIVA_HW_INST *chip
+)
+{
+ return ((!(chip->PFIFO[0x00001214/4] & 0x10)) | (chip->PGRAPH[0x00000700/4] & 0x01));
+}
+static int ShowHideCursor
+(
+ RIVA_HW_INST *chip,
+ int ShowHide
+)
+{
+ int current;
+ current = chip->CurrentState->cursor1;
+ chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) | (ShowHide & 0x01);
+ outb(0x3D4,0x31);
+ outb(0x3D5, chip->CurrentState->cursor1);
+ return (current & 0x01);
+}
+
+/****************************************************************************\
+* *
+* The video arbitration routines calculate some "magic" numbers. Fixes *
+* the snow seen when accessing the framebuffer without it. *
+* It just works (I hope). *
+* *
+\****************************************************************************/
+
+#define DEFAULT_GR_LWM 100
+#define DEFAULT_VID_LWM 100
+#define DEFAULT_GR_BURST_SIZE 256
+#define DEFAULT_VID_BURST_SIZE 128
+#define VIDEO 0
+#define GRAPHICS 1
+#define MPORT 2
+#define ENGINE 3
+#define GFIFO_SIZE 320
+#define GFIFO_SIZE_128 256
+#define MFIFO_SIZE 120
+#define VFIFO_SIZE 256
+#define ABS(a) (a>0?a:-a)
+typedef struct {
+ int gdrain_rate;
+ int vdrain_rate;
+ int mdrain_rate;
+ int gburst_size;
+ int vburst_size;
+ char vid_en;
+ char gr_en;
+ int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm;
+ int by_gfacc;
+ char vid_only_once;
+ char gr_only_once;
+ char first_vacc;
+ char first_gacc;
+ char first_macc;
+ int vocc;
+ int gocc;
+ int mocc;
+ char cur;
+ char engine_en;
+ char converged;
+ int priority;
+} nv3_arb_info;
+typedef struct {
+ int graphics_lwm;
+ int video_lwm;
+ int graphics_burst_size;
+ int video_burst_size;
+ int graphics_hi_priority;
+ int media_hi_priority;
+ int rtl_values;
+ int valid;
+} nv3_fifo_info;
+typedef struct {
+ char pix_bpp;
+ char enable_video;
+ char gr_during_vid;
+ char enable_mp;
+ int memory_width;
+ int video_scale;
+ int pclk_khz;
+ int mclk_khz;
+ int mem_page_miss;
+ int mem_latency;
+ char mem_aligned;
+} nv3_sim_state;
+typedef struct {
+ int graphics_lwm;
+ int video_lwm;
+ int graphics_burst_size;
+ int video_burst_size;
+ int valid;
+} nv4_fifo_info;
+typedef struct {
+ int pclk_khz;
+ int mclk_khz;
+ int nvclk_khz;
+ char mem_page_miss;
+ char mem_latency;
+ int memory_width;
+ char enable_video;
+ char gr_during_vid;
+ char pix_bpp;
+ char mem_aligned;
+ char enable_mp;
+} nv4_sim_state;
+static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
+{
+ int iter = 0;
+ int tmp;
+ int vfsize, mfsize, gfsize;
+ int mburst_size = 32;
+ int mmisses, gmisses, vmisses;
+ int misses;
+ int vlwm, glwm, mlwm;
+ int last, next, cur;
+ int max_gfsize ;
+ long ns;
+
+ vlwm = 0;
+ glwm = 0;
+ mlwm = 0;
+ vfsize = 0;
+ gfsize = 0;
+ cur = ainfo->cur;
+ mmisses = 2;
+ gmisses = 2;
+ vmisses = 2;
+ if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128;
+ else max_gfsize = GFIFO_SIZE;
+ max_gfsize = GFIFO_SIZE;
+ while (1)
+ {
+ if (ainfo->vid_en)
+ {
+ if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc;
+ if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ;
+ ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
+ vfsize = ns * ainfo->vdrain_rate / 1000000;
+ vfsize = ainfo->wcvlwm - ainfo->vburst_size + vfsize;
+ }
+ if (state->enable_mp)
+ {
+ if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc;
+ }
+ if (ainfo->gr_en)
+ {
+ if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ;
+ if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc;
+ ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
+ gfsize = ns *ainfo->gdrain_rate/1000000;
+ gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize;
+ }
+ mfsize = 0;
+ if (!state->gr_during_vid && ainfo->vid_en) {
+ if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once)
+ next = VIDEO;
+ else if (ainfo->mocc < 0)
+ next = MPORT;
+ else if (ainfo->gocc< ainfo->by_gfacc)
+ next = GRAPHICS;
+ else return (0);
+ }
+ else switch (ainfo->priority)
+ {
+ case VIDEO:
+ if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+ next = VIDEO;
+ else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+ next = GRAPHICS;
+ else if (ainfo->mocc<0)
+ next = MPORT;
+ else return (0);
+ break;
+ case GRAPHICS:
+ if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+ next = GRAPHICS;
+ else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+ next = VIDEO;
+ else if (ainfo->mocc<0)
+ next = MPORT;
+ else return (0);
+ break;
+ default:
+ if (ainfo->mocc<0)
+ next = MPORT;
+ else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+ next = GRAPHICS;
+ else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+ next = VIDEO;
+ else return (0);
+ break;
+ }
+ last = cur;
+ cur = next;
+ iter++;
+ switch (cur)
+ {
+ case VIDEO:
+ if (last==cur) misses = 0;
+ else if (ainfo->first_vacc) misses = vmisses;
+ else misses = 1;
+ ainfo->first_vacc = 0;
+ if (last!=cur)
+ {
+ ns = 1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
+ vlwm = ns * ainfo->vdrain_rate/ 1000000;
+ vlwm = ainfo->vocc - vlwm;
+ }
+ ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz;
+ ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000;
+ ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000;
+ ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000;
+ break;
+ case GRAPHICS:
+ if (last==cur) misses = 0;
+ else if (ainfo->first_gacc) misses = gmisses;
+ else misses = 1;
+ ainfo->first_gacc = 0;
+ if (last!=cur)
+ {
+ ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ;
+ glwm = ns * ainfo->gdrain_rate/1000000;
+ glwm = ainfo->gocc - glwm;
+ }
+ ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
+ ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
+ ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000;
+ ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000;
+ break;
+ default:
+ if (last==cur) misses = 0;
+ else if (ainfo->first_macc) misses = mmisses;
+ else misses = 1;
+ ainfo->first_macc = 0;
+ ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz;
+ ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
+ ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000;
+ ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000;
+ break;
+ }
+ if (iter>100)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz;
+ tmp = ns * ainfo->gdrain_rate/1000000;
+ if (ABS(ainfo->gburst_size) + ((ABS(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
+ tmp = ns * ainfo->vdrain_rate/1000000;
+ if (ABS(ainfo->vburst_size) + (ABS(ainfo->wcvlwm + 32) & ~0xf) - tmp> VFIFO_SIZE)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(ainfo->gocc) > max_gfsize)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(ainfo->vocc) > VFIFO_SIZE)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(ainfo->mocc) > MFIFO_SIZE)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(vfsize) > VFIFO_SIZE)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(gfsize) > max_gfsize)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ if (ABS(mfsize) > MFIFO_SIZE)
+ {
+ ainfo->converged = 0;
+ return (1);
+ }
+ }
+}
+static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
+{
+ long ens, vns, mns, gns;
+ int mmisses, gmisses, vmisses, eburst_size, mburst_size;
+ int refresh_cycle;
+
+ refresh_cycle = 0;
+ refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5;
+ mmisses = 2;
+ if (state->mem_aligned) gmisses = 2;
+ else gmisses = 3;
+ vmisses = 2;
+ eburst_size = state->memory_width * 1;
+ mburst_size = 32;
+ gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
+ ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
+ ainfo->wcmocc = 0;
+ ainfo->wcgocc = 0;
+ ainfo->wcvocc = 0;
+ ainfo->wcvlwm = 0;
+ ainfo->wcglwm = 0;
+ ainfo->engine_en = 1;
+ ainfo->converged = 1;
+ if (ainfo->engine_en)
+ {
+ ens = 1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz;
+ ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0;
+ ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0;
+ ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0;
+ ainfo->cur = ENGINE;
+ ainfo->first_vacc = 1;
+ ainfo->first_gacc = 1;
+ ainfo->first_macc = 1;
+ nv3_iterate(res_info, state,ainfo);
+ }
+ if (state->enable_mp)
+ {
+ mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+ ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000;
+ ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000;
+ ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000;
+ ainfo->cur = MPORT;
+ ainfo->first_vacc = 1;
+ ainfo->first_gacc = 1;
+ ainfo->first_macc = 0;
+ nv3_iterate(res_info, state,ainfo);
+ }
+ if (ainfo->gr_en)
+ {
+ ainfo->first_vacc = 1;
+ ainfo->first_gacc = 0;
+ ainfo->first_macc = 1;
+ gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+ ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000;
+ ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0;
+ ainfo->mocc = state->enable_mp ? 0-gns*ainfo->mdrain_rate/1000000: 0;
+ ainfo->cur = GRAPHICS;
+ nv3_iterate(res_info, state,ainfo);
+ }
+ if (ainfo->vid_en)
+ {
+ ainfo->first_vacc = 0;
+ ainfo->first_gacc = 1;
+ ainfo->first_macc = 1;
+ vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+ ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000;
+ ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0;
+ ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ;
+ ainfo->cur = VIDEO;
+ nv3_iterate(res_info, state, ainfo);
+ }
+ if (ainfo->converged)
+ {
+ res_info->graphics_lwm = (int)ABS(ainfo->wcglwm) + 16;
+ res_info->video_lwm = (int)ABS(ainfo->wcvlwm) + 32;
+ res_info->graphics_burst_size = ainfo->gburst_size;
+ res_info->video_burst_size = ainfo->vburst_size;
+ res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS);
+ res_info->media_hi_priority = (ainfo->priority == MPORT);
+ if (res_info->video_lwm > 160)
+ {
+ res_info->graphics_lwm = 256;
+ res_info->video_lwm = 128;
+ res_info->graphics_burst_size = 64;
+ res_info->video_burst_size = 64;
+ res_info->graphics_hi_priority = 0;
+ res_info->media_hi_priority = 0;
+ ainfo->converged = 0;
+ return (0);
+ }
+ if (res_info->video_lwm > 128)
+ {
+ res_info->video_lwm = 128;
+ }
+ return (1);
+ }
+ else
+ {
+ res_info->graphics_lwm = 256;
+ res_info->video_lwm = 128;
+ res_info->graphics_burst_size = 64;
+ res_info->video_burst_size = 64;
+ res_info->graphics_hi_priority = 0;
+ res_info->media_hi_priority = 0;
+ return (0);
+ }
+}
+static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
+{
+ int done, g,v, p;
+
+ done = 0;
+ if (state->gr_during_vid && ainfo->vid_en)
+ ainfo->priority = MPORT;
+ else
+ ainfo->priority = ainfo->gdrain_rate < ainfo->vdrain_rate ? VIDEO: GRAPHICS;
+ for (p=0; p < 2 && done != 1; p++)
+ {
+ for (g=128 ; (g > 32) && (done != 1); g= g>> 1)
+ {
+ for (v=128; (v >=32) && (done !=1); v = v>> 1)
+ {
+ ainfo->priority = p;
+ ainfo->gburst_size = g;
+ ainfo->vburst_size = v;
+ done = nv3_arb(res_info, state,ainfo);
+ if (g==128)
+ {
+ if ((res_info->graphics_lwm + g) > 256)
+ done = 0;
+ }
+ }
+ }
+ }
+ if (!done)
+ return (0);
+ else
+ return (1);
+}
+static void nv3CalcArbitration
+(
+ nv3_fifo_info * res_info,
+ nv3_sim_state * state
+)
+{
+ nv3_fifo_info save_info;
+ nv3_arb_info ainfo;
+ char res_gr, res_vid;
+
+ ainfo.gr_en = 1;
+ ainfo.vid_en = state->enable_video;
+ ainfo.vid_only_once = 0;
+ ainfo.gr_only_once = 0;
+ ainfo.gdrain_rate = (int) state->pclk_khz * state -> pix_bpp/8;
+ ainfo.vdrain_rate = (int) state->pclk_khz * 2;
+ if (state->video_scale != 0)
+ ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale;
+ ainfo.mdrain_rate = 33000;
+ res_info->rtl_values = 0;
+ if (!state->gr_during_vid && state->enable_video)
+ {
+ ainfo.gr_only_once = 1;
+ ainfo.gr_en = 1;
+ ainfo.gdrain_rate = 0;
+ res_vid = nv3_get_param(res_info, state, &ainfo);
+ res_vid = ainfo.converged;
+ save_info.video_lwm = res_info->video_lwm;
+ save_info.video_burst_size = res_info->video_burst_size;
+ ainfo.vid_en = 1;
+ ainfo.vid_only_once = 1;
+ ainfo.gr_en = 1;
+ ainfo.gdrain_rate = (int) state->pclk_khz * state -> pix_bpp/8;
+ ainfo.vdrain_rate = 0;
+ res_gr = nv3_get_param(res_info, state, &ainfo);
+ res_gr = ainfo.converged;
+ res_info->video_lwm = save_info.video_lwm;
+ res_info->video_burst_size = save_info.video_burst_size;
+ res_info->valid = res_gr & res_vid;
+ }
+ else
+ {
+ if (!ainfo.gr_en) ainfo.gdrain_rate = 0;
+ if (!ainfo.vid_en) ainfo.vdrain_rate = 0;
+ res_gr = nv3_get_param(res_info, state, &ainfo);
+ res_info->valid = ainfo.converged;
+ }
+}
+void nv3UpdateArbitrationSettings
+(
+ unsigned VClk,
+ unsigned pixelDepth,
+ unsigned *burst,
+ unsigned *lwm,
+ RIVA_HW_INST *chip
+)
+{
+ nv3_fifo_info fifo_data;
+ nv3_sim_state sim_data;
+ unsigned int M, N, P, pll, MClk;
+
+ pll = chip->PRAMDAC[0x00000504/4];
+ M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
+ MClk = (N * chip->CrystalFreqKHz / M) >> P;
+ sim_data.pix_bpp = (char)pixelDepth;
+ sim_data.enable_video = 0;
+ sim_data.enable_mp = 0;
+ sim_data.video_scale = 1;
+ sim_data.memory_width = (chip->PEXTDEV[0x00000000/4] & 0x10) ? 128 : 64;
+ sim_data.memory_width = 128;
+ sim_data.mem_latency = 11;
+ sim_data.mem_aligned = 1;
+ sim_data.mem_page_miss = 9;
+ sim_data.gr_during_vid = 0;
+ sim_data.pclk_khz = VClk;
+ sim_data.mclk_khz = MClk;
+ nv3CalcArbitration(&fifo_data, &sim_data);
+ if (fifo_data.valid)
+ {
+ int b = fifo_data.graphics_burst_size >> 4;
+ *burst = 0;
+ while (b >>= 1) (*burst)++;
+ *lwm = fifo_data.graphics_lwm >> 3;
+ }
+ else
+ {
+ *lwm = 0x24;
+ *burst = 0x02;
+ }
+}
+static void nv4CalcArbitration
+(
+ nv4_fifo_info *fifo,
+ nv4_sim_state *arb
+)
+{
+ int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
+ int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+ int found, mclk_extra, mclk_loop, cbs, m1, p1;
+ int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+ int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
+ int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
+ int craw, vraw;
+
+ fifo->valid = 1;
+ pclk_freq = arb->pclk_khz;
+ mclk_freq = arb->mclk_khz;
+ nvclk_freq = arb->nvclk_khz;
+ pagemiss = arb->mem_page_miss;
+ cas = arb->mem_latency;
+ width = arb->memory_width >> 6;
+ video_enable = arb->enable_video;
+ color_key_enable = arb->gr_during_vid;
+ bpp = arb->pix_bpp;
+ align = arb->mem_aligned;
+ mp_enable = arb->enable_mp;
+ clwm = 0;
+ vlwm = 0;
+ cbs = 128;
+ pclks = 2;
+ nvclks = 2;
+ nvclks += 2;
+ nvclks += 1;
+ mclks = 5;
+ mclks += 3;
+ mclks += 1;
+ mclks += cas;
+ mclks += 1;
+ mclks += 1;
+ mclks += 1;
+ mclks += 1;
+ mclk_extra = 3;
+ nvclks += 2;
+ nvclks += 1;
+ nvclks += 1;
+ nvclks += 1;
+ if (mp_enable)
+ mclks+=4;
+ nvclks += 0;
+ pclks += 0;
+ found = 0;
+ vbs = 0;
+ while (found != 1)
+ {
+ fifo->valid = 1;
+ found = 1;
+ mclk_loop = mclks+mclk_extra;
+ us_m = mclk_loop *1000*1000 / mclk_freq;
+ us_n = nvclks*1000*1000 / nvclk_freq;
+ us_p = nvclks*1000*1000 / pclk_freq;
+ if (video_enable)
+ {
+ video_drain_rate = pclk_freq * 2;
+ crtc_drain_rate = pclk_freq * bpp/8;
+ vpagemiss = 2;
+ vpagemiss += 1;
+ crtpagemiss = 2;
+ vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
+ if (nvclk_freq * 2 > mclk_freq * width)
+ video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
+ else
+ video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
+ us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
+ vlwm = us_video * video_drain_rate/(1000*1000);
+ vlwm++;
+ vbs = 128;
+ if (vlwm > 128) vbs = 64;
+ if (vlwm > (256-64)) vbs = 32;
+ if (nvclk_freq * 2 > mclk_freq * width)
+ video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
+ else
+ video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
+ cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
+ us_crt =
+ us_video
+ +video_fill_us
+ +cpm_us
+ +us_m + us_n +us_p
+ ;
+ clwm = us_crt * crtc_drain_rate/(1000*1000);
+ clwm++;
+ }
+ else
+ {
+ crtc_drain_rate = pclk_freq * bpp/8;
+ crtpagemiss = 2;
+ crtpagemiss += 1;
+ cpm_us = crtpagemiss * pagemiss *1000*1000/ mclk_freq;
+ us_crt = cpm_us + us_m + us_n + us_p ;
+ clwm = us_crt * crtc_drain_rate/(1000*1000);
+ clwm++;
+ }
+ m1 = clwm + cbs - 512;
+ p1 = m1 * pclk_freq / mclk_freq;
+ p1 = p1 * bpp / 8;
+ if ((p1 < m1) && (m1 > 0))
+ {
+ fifo->valid = 0;
+ found = 0;
+ if (mclk_extra ==0) found = 1;
+ mclk_extra--;
+ }
+ else if (video_enable)
+ {
+ if ((clwm > 511) || (vlwm > 255))
+ {
+ fifo->valid = 0;
+ found = 0;
+ if (mclk_extra ==0) found = 1;
+ mclk_extra--;
+ }
+ }
+ else
+ {
+ if (clwm > 519)
+ {
+ fifo->valid = 0;
+ found = 0;
+ if (mclk_extra ==0) found = 1;
+ mclk_extra--;
+ }
+ }
+ craw = clwm;
+ vraw = vlwm;
+ if (clwm < 384) clwm = 384;
+ if (vlwm < 128) vlwm = 128;
+ data = (int)(clwm);
+ fifo->graphics_lwm = data;
+ fifo->graphics_burst_size = 128;
+ data = (int)((vlwm+15));
+ fifo->video_lwm = data;
+ fifo->video_burst_size = vbs;
+ }
+}
+static void nv4UpdateArbitrationSettings
+(
+ unsigned VClk,
+ unsigned pixelDepth,
+ unsigned *burst,
+ unsigned *lwm,
+ RIVA_HW_INST *chip
+)
+{
+ nv4_fifo_info fifo_data;
+ nv4_sim_state sim_data;
+ unsigned int M, N, P, pll, MClk, NVClk, cfg1;
+
+ pll = chip->PRAMDAC[0x00000504/4];
+ M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
+ MClk = (N * chip->CrystalFreqKHz / M) >> P;
+ pll = chip->PRAMDAC[0x00000500/4];
+ M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
+ NVClk = (N * chip->CrystalFreqKHz / M) >> P;
+ cfg1 = chip->PFB[0x00000204/4];
+ sim_data.pix_bpp = (char)pixelDepth;
+ sim_data.enable_video = 0;
+ sim_data.enable_mp = 0;
+ sim_data.memory_width = (chip->PEXTDEV[0x00000000/4] & 0x10) ? 128 : 64;
+ sim_data.mem_latency = (char)cfg1 & 0x0F;
+ sim_data.mem_aligned = 1;
+ sim_data.mem_page_miss = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
+ sim_data.gr_during_vid = 0;
+ sim_data.pclk_khz = VClk;
+ sim_data.mclk_khz = MClk;
+ sim_data.nvclk_khz = NVClk;
+ nv4CalcArbitration(&fifo_data, &sim_data);
+ if (fifo_data.valid)
+ {
+ int b = fifo_data.graphics_burst_size >> 4;
+ *burst = 0;
+ while (b >>= 1) (*burst)++;
+ *lwm = fifo_data.graphics_lwm >> 3;
+ }
+}
+
+/****************************************************************************\
+* *
+* RIVA Mode State Routines *
+* *
+\****************************************************************************/
+
+/*
+ * Calculate the Video Clock parameters for the PLL.
+ */
+static int CalcVClock
+(
+ int clockIn,
+ int *clockOut,
+ int *mOut,
+ int *nOut,
+ int *pOut,
+ RIVA_HW_INST *chip
+)
+{
+ unsigned lowM, highM, highP;
+ unsigned DeltaNew, DeltaOld;
+ unsigned VClk, Freq;
+ unsigned M, N, P;
+
+ DeltaOld = 0xFFFFFFFF;
+ VClk = (unsigned)clockIn;
+ if (chip->CrystalFreqKHz == 14318)
+ {
+ lowM = 8;
+ highM = 14 - (chip->Architecture == 3);
+ }
+ else
+ {
+ lowM = 7;
+ highM = 13 - (chip->Architecture == 3);
+ }
+ highP = 4 - (chip->Architecture == 3);
+ for (P = 0; P <= highP; P ++)
+ {
+ Freq = VClk << P;
+ if ((Freq >= 128000) && (Freq <= chip->MaxVClockFreqKHz))
+ {
+ for (M = lowM; M <= highM; M++)
+ {
+ N = (VClk * M / chip->CrystalFreqKHz) << P;
+ Freq = (chip->CrystalFreqKHz * N / M) >> P;
+ if (Freq > VClk)
+ DeltaNew = Freq - VClk;
+ else
+ DeltaNew = VClk - Freq;
+ if (DeltaNew < DeltaOld)
+ {
+ *mOut = M;
+ *nOut = N;
+ *pOut = P;
+ *clockOut = Freq;
+ DeltaOld = DeltaNew;
+ }
+ }
+ }
+ }
+ return (DeltaOld != 0xFFFFFFFF);
+}
+/*
+ * Calculate extended mode parameters (SVGA) and save in a
+ * mode state structure.
+ */
+static void CalcStateExt
+(
+ RIVA_HW_INST *chip,
+ RIVA_HW_STATE *state,
+ int bpp,
+ int width,
+ int hDisplaySize,
+ int hDisplay,
+ int hStart,
+ int hEnd,
+ int hTotal,
+ int height,
+ int vDisplay,
+ int vStart,
+ int vEnd,
+ int vTotal,
+ int dotClock
+)
+{
+ int pixelDepth, VClk, m, n, p;
+ /*
+ * Save mode parameters.
+ */
+ state->bpp = bpp;
+ state->width = width;
+ state->height = height;
+ /*
+ * Extended RIVA registers.
+ */
+ pixelDepth = (bpp + 1)/8;
+ CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
+ switch (chip->Architecture)
+ {
+ case 3:
+ nv3UpdateArbitrationSettings(VClk,
+ pixelDepth * 8,
+ &(state->arbitration0),
+ &(state->arbitration1),
+ chip);
+ state->cursor0 = 0x00;
+ state->cursor1 = 0x78;
+ state->cursor2 = 0x00000000;
+ state->pllsel = 0x10010100;
+ state->config = ((width + 31)/32)
+ | (((pixelDepth > 2) ? 3 : pixelDepth) << 8)
+ | 0x1000;
+ state->general = 0x00000100;
+ state->repaint1 = hDisplaySize < 1280 ? 0x06 : 0x02;
+ break;
+ case 4:
+ nv4UpdateArbitrationSettings(VClk,
+ pixelDepth * 8,
+ &(state->arbitration0),
+ &(state->arbitration1),
+ chip);
+ state->cursor0 = 0x00;
+ state->cursor1 = 0xFC;
+ state->cursor2 = 0x00000000;
+ state->pllsel = 0x10000700;
+ state->config = 0x00001114;
+ state->general = bpp == 16 ? 0x00101100 : 0x00100100;
+ state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+ break;
+ }
+ state->vpll = (p << 16) | (n << 8) | m;
+ state->screen = ((hTotal & 0x040) >> 2)
+ | ((vDisplay & 0x400) >> 7)
+ | ((vStart & 0x400) >> 8)
+ | ((vDisplay & 0x400) >> 9)
+ | ((vTotal & 0x400) >> 10);
+ state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3;
+ state->horiz = hTotal < 260 ? 0x00 : 0x01;
+ state->pixel = pixelDepth > 2 ? 3 : pixelDepth;
+ state->offset0 =
+ state->offset1 =
+ state->offset2 =
+ state->offset3 = 0;
+ state->pitch0 =
+ state->pitch1 =
+ state->pitch2 =
+ state->pitch3 = pixelDepth * width;
+}
+/*
+ * Load fixed function state and pre-calculated/stored state.
+ */
+#define LOAD_FIXED_STATE(tbl,dev) \
+ for (i = 0; i < sizeof(tbl##Table##dev)/8; i++) \
+ chip->dev[tbl##Table##dev[i][0]] = tbl##Table##dev[i][1]
+#define LOAD_FIXED_STATE_8BPP(tbl,dev) \
+ for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++) \
+ chip->dev[tbl##Table##dev##_8BPP[i][0]] = tbl##Table##dev##_8BPP[i][1]
+#define LOAD_FIXED_STATE_15BPP(tbl,dev) \
+ for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++) \
+ chip->dev[tbl##Table##dev##_15BPP[i][0]] = tbl##Table##dev##_15BPP[i][1]
+#define LOAD_FIXED_STATE_16BPP(tbl,dev) \
+ for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++) \
+ chip->dev[tbl##Table##dev##_16BPP[i][0]] = tbl##Table##dev##_16BPP[i][1]
+#define LOAD_FIXED_STATE_32BPP(tbl,dev) \
+ for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++) \
+ chip->dev[tbl##Table##dev##_32BPP[i][0]] = tbl##Table##dev##_32BPP[i][1]
+static void LoadStateExt
+(
+ RIVA_HW_INST *chip,
+ RIVA_HW_STATE *state,
+ int all
+)
+{
+ int i;
+
+ /*
+ * Load HW fixed function state.
+ */
+ LOAD_FIXED_STATE(Riva,PMC);
+ LOAD_FIXED_STATE(Riva,PTIMER);
+ /*
+ * Make sure frame buffer config gets set before loading PRAMIN.
+ */
+ chip->PFB[0x00000200/4] = state->config;
+ switch (chip->Architecture)
+ {
+ case 3:
+ LOAD_FIXED_STATE(nv3,PFIFO);
+ LOAD_FIXED_STATE(nv3,PRAMIN);
+ LOAD_FIXED_STATE(nv3,PGRAPH);
+ switch (state->bpp)
+ {
+ case 15:
+ case 16:
+ LOAD_FIXED_STATE_15BPP(nv3,PRAMIN);
+ LOAD_FIXED_STATE_15BPP(nv3,PGRAPH);
+ chip->Tri03 = (RivaTexturedTriangle03 *)&(chip->FIFO[0x0000E000/4]);
+ break;
+ case 24:
+ case 32:
+ LOAD_FIXED_STATE_32BPP(nv3,PRAMIN);
+ LOAD_FIXED_STATE_32BPP(nv3,PGRAPH);
+ chip->Tri03 = 0L;
+ break;
+ case 8:
+ default:
+ LOAD_FIXED_STATE_8BPP(nv3,PRAMIN);
+ LOAD_FIXED_STATE_8BPP(nv3,PGRAPH);
+ chip->Tri03 = 0L;
+ break;
+ }
+ for (i = 0x00000; i < 0x00800; i++)
+ chip->PRAMIN[0x00000502 + i] = (i << 12) | 0x03;
+ chip->PGRAPH[0x00000630/4] = state->offset0;
+ chip->PGRAPH[0x00000634/4] = state->offset1;
+ chip->PGRAPH[0x00000638/4] = state->offset2;
+ chip->PGRAPH[0x0000063C/4] = state->offset3;
+ chip->PGRAPH[0x00000650/4] = state->pitch0;
+ chip->PGRAPH[0x00000654/4] = state->pitch1;
+ chip->PGRAPH[0x00000658/4] = state->pitch2;
+ chip->PGRAPH[0x0000065C/4] = state->pitch3;
+ break;
+ case 4:
+ LOAD_FIXED_STATE(nv4,PFIFO);
+ LOAD_FIXED_STATE(nv4,PRAMIN);
+ LOAD_FIXED_STATE(nv4,PGRAPH);
+ switch (state->bpp)
+ {
+ case 15:
+ LOAD_FIXED_STATE_15BPP(nv4,PRAMIN);
+ LOAD_FIXED_STATE_15BPP(nv4,PGRAPH);
+ chip->Tri03 = (RivaTexturedTriangle03 *)&(chip->FIFO[0x0000E000/4]);
+ break;
+ case 16:
+ LOAD_FIXED_STATE_16BPP(nv4,PRAMIN);
+ LOAD_FIXED_STATE_16BPP(nv4,PGRAPH);
+ chip->Tri03 = (RivaTexturedTriangle03 *)&(chip->FIFO[0x0000E000/4]);
+ break;
+ case 24:
+ case 32:
+ LOAD_FIXED_STATE_32BPP(nv4,PRAMIN);
+ LOAD_FIXED_STATE_32BPP(nv4,PGRAPH);
+ chip->Tri03 = 0L;
+ break;
+ case 8:
+ default:
+ LOAD_FIXED_STATE_8BPP(nv4,PRAMIN);
+ LOAD_FIXED_STATE_8BPP(nv4,PGRAPH);
+ chip->Tri03 = 0L;
+ break;
+ }
+ chip->PGRAPH[0x00000640/4] = state->offset0;
+ chip->PGRAPH[0x00000644/4] = state->offset1;
+ chip->PGRAPH[0x00000648/4] = state->offset2;
+ chip->PGRAPH[0x0000064C/4] = state->offset3;
+ chip->PGRAPH[0x00000670/4] = state->pitch0;
+ chip->PGRAPH[0x00000674/4] = state->pitch1;
+ chip->PGRAPH[0x00000678/4] = state->pitch2;
+ chip->PGRAPH[0x0000067C/4] = state->pitch3;
+ break;
+ }
+ LOAD_FIXED_STATE(Riva,FIFO);
+ /*
+ * Load HW mode state.
+ */
+ /* slh: added the if (all) checks */
+ outb(0x3D4,0x19); outb(0x3D5, state->repaint0);
+ outb(0x3D4,0x1A); outb(0x3D5, state->repaint1);
+ if (all) {
+ outb(0x3D4,0x25); outb(0x3D5, state->screen);
+ }
+ outb(0x3D4,0x28); outb(0x3D5, state->pixel);
+ if (all) {
+ outb(0x3D4,0x2D); outb(0x3D5, state->horiz);
+ outb(0x3D4,0x1B); outb(0x3D5, state->arbitration0);
+ outb(0x3D4,0x20); outb(0x3D5, state->arbitration1);
+ }
+ outb(0x3D4,0x30); outb(0x3D5, state->cursor0);
+ outb(0x3D4,0x31); outb(0x3D5, state->cursor1);
+ chip->PRAMDAC[0x00000300/4] = state->cursor2;
+ if (all) {
+ chip->PRAMDAC[0x00000508/4] = state->vpll;
+ }
+ chip->PRAMDAC[0x0000050C/4] = state->pllsel;
+ chip->PRAMDAC[0x00000600/4] = state->general;
+
+ /*
+ * Turn off VBlank enable and reset.
+ */
+ *(chip->VBLANKENABLE) = 0;
+ *(chip->VBLANK) = chip->VBlankBit;
+ /*
+ * Set interrupt enable.
+ */
+ chip->PMC[0x00000140/4] = chip->EnableIRQ & 0x01;
+ /*
+ * Set current state pointer.
+ */
+ chip->CurrentState = state;
+ /*
+ * Reset FIFO free count.
+ */
+ chip->FifoFreeCount = 0;
+}
+static void UnloadStateExt
+(
+ RIVA_HW_INST *chip,
+ RIVA_HW_STATE *state
+)
+{
+ /*
+ * Save current HW state.
+ */
+ outb(0x3D4,0x19); state->repaint0 = inb(0x3D5);
+ outb(0x3D4,0x1A); state->repaint1 = inb(0x3D5);
+ outb(0x3D4,0x25); state->screen = inb(0x3D5);
+ outb(0x3D4,0x28); state->pixel = inb(0x3D5);
+ outb(0x3D4,0x2D); state->horiz = inb(0x3D5);
+ outb(0x3D4,0x1B); state->arbitration0 = inb(0x3D5);
+ outb(0x3D4,0x20); state->arbitration1 = inb(0x3D5);
+ outb(0x3D4,0x30); state->cursor0 = inb(0x3D5);
+ outb(0x3D4,0x31); state->cursor1 = inb(0x3D5);
+ state->cursor2 = chip->PRAMDAC[0x00000300/4];
+ state->vpll = chip->PRAMDAC[0x00000508/4];
+ state->pllsel = chip->PRAMDAC[0x0000050C/4];
+ state->general = chip->PRAMDAC[0x00000600/4];
+ state->config = chip->PFB[0x00000200/4];
+ switch (chip->Architecture)
+ {
+ case 3:
+ state->offset0 = chip->PGRAPH[0x00000630/4];
+ state->offset1 = chip->PGRAPH[0x00000634/4];
+ state->offset2 = chip->PGRAPH[0x00000638/4];
+ state->offset3 = chip->PGRAPH[0x0000063C/4];
+ state->pitch0 = chip->PGRAPH[0x00000650/4];
+ state->pitch1 = chip->PGRAPH[0x00000654/4];
+ state->pitch2 = chip->PGRAPH[0x00000658/4];
+ state->pitch3 = chip->PGRAPH[0x0000065C/4];
+ break;
+ case 4:
+ state->offset0 = chip->PGRAPH[0x00000640/4];
+ state->offset1 = chip->PGRAPH[0x00000644/4];
+ state->offset2 = chip->PGRAPH[0x00000648/4];
+ state->offset3 = chip->PGRAPH[0x0000064C/4];
+ state->pitch0 = chip->PGRAPH[0x00000670/4];
+ state->pitch1 = chip->PGRAPH[0x00000674/4];
+ state->pitch2 = chip->PGRAPH[0x00000678/4];
+ state->pitch3 = chip->PGRAPH[0x0000067C/4];
+ break;
+ }
+}
+static void SetStartAddress
+(
+ RIVA_HW_INST *chip,
+ unsigned start
+)
+{
+ int offset = start >> 2;
+ int pan = (start & 3) << 1;
+ unsigned char tmp;
+
+ /*
+ * Unlock extended registers.
+ */
+ outb(chip->LockUnlockIO, chip->LockUnlockIndex);
+ outb(chip->LockUnlockIO + 1, 0x57);
+
+ /*
+ * Set start address.
+ */
+ outb(0x3D4, 0x0D);
+ outb(0x3D5, offset);
+ outb(0x3D4, 0x0C);
+ outb(0x3D5, offset >> 8);
+
+ /* slh: added the TNT version of this routine. Not sure what this
+ * really should be, but the changed code works on my TNT, where
+ * the original did not.
+ */
+ if (chip->Architecture > 3) {
+ /* TNT */
+ outb(0x3D4, 0x19);
+ tmp = inb(0x3D5);
+ outb(0x3D5, ((offset >> 16) & 0x1F) | (tmp & 0xE0));
+
+ outb(0x3D4, 0x2D);
+ tmp = inb(0x3D5);
+ outb(0x3D5, ((offset >> 16) & 0x20) | (tmp & 0xDF));
+ }
+ else {
+ /* Riva 128 */
+ outb(0x3D4, 0x19);
+ tmp = inb(0x3D5);
+ outb(0x3D5, ((offset >> 16) & 0x0F) | (tmp & 0xF0));
+ }
+
+ /*
+ * 4 pixel pan register.
+ */
+ offset = inb(chip->IO + 0x0A);
+ outb(0x3C0, 0x13);
+ outb(0x3C0, pan);
+}
+static void nv3SetSurfaces2D
+(
+ RIVA_HW_INST *chip,
+ unsigned surf0,
+ unsigned surf1
+)
+{
+ while (nv3Busy(chip));
+ chip->PGRAPH[0x00000630/4] = surf0;
+ chip->PGRAPH[0x00000634/4] = surf1;
+}
+static void nv4SetSurfaces2D
+(
+ RIVA_HW_INST *chip,
+ unsigned surf0,
+ unsigned surf1
+)
+{
+ while (nv4Busy(chip));
+ chip->PGRAPH[0x00000640/4] = surf0;
+ chip->PGRAPH[0x00000644/4] = surf1;
+}
+static void nv3SetSurfaces3D
+(
+ RIVA_HW_INST *chip,
+ unsigned surf0,
+ unsigned surf1
+)
+{
+ while (nv3Busy(chip));
+ chip->PGRAPH[0x00000638/4] = surf0;
+ chip->PGRAPH[0x0000063C/4] = surf1;
+}
+static void nv4SetSurfaces3D
+(
+ RIVA_HW_INST *chip,
+ unsigned surf0,
+ unsigned surf1
+)
+{
+ while (nv4Busy(chip));
+ chip->PGRAPH[0x00000648/4] = surf0;
+ chip->PGRAPH[0x0000064C/4] = surf1;
+}
+
+/****************************************************************************\
+* *
+* Probe RIVA Chip Configuration *
+* *
+\****************************************************************************/
+
+void nv3GetConfig
+(
+ RIVA_HW_INST *chip
+)
+{
+ /*
+ * Fill in chip configuration.
+ */
+ if (chip->PFB[0x00000000/4] & 0x00000020)
+ {
+ if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
+ && ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02))
+ {
+ /*
+ * SDRAM 128 ZX.
+ */
+ chip->RamBandwidthKBytesPerSec = 800000;
+ switch (chip->PFB[0x00000000/4] & 0x03)
+ {
+ case 2:
+ chip->RamAmountKBytes = 1024 * 4 - 32;
+ break;
+ case 1:
+ chip->RamAmountKBytes = 1024 * 2 - 32;
+ break;
+ default:
+ chip->RamAmountKBytes = 1024 * 8 - 32;
+ break;
+ }
+ }
+ else
+ {
+ chip->RamBandwidthKBytesPerSec = 1000000;
+ chip->RamAmountKBytes = 1024 * 8 - 32;
+ }
+ }
+ else
+ {
+ /*
+ * SGRAM 128.
+ */
+ chip->RamBandwidthKBytesPerSec = 1000000;
+ switch (chip->PFB[0x00000000/4] & 0x00000003)
+ {
+ case 0:
+ chip->RamAmountKBytes = 1024 * 8 - 32;
+ break;
+ case 2:
+ chip->RamAmountKBytes = 1024 * 4 - 32;
+ break;
+ default:
+ chip->RamAmountKBytes = 1024 * 2 - 32;
+ break;
+ }
+ }
+ chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000020) ? 14318 : 13500;
+ chip->CURSOR = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]);
+ chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]);
+ chip->VBLANKENABLE = &(chip->PGRAPH[0x0140/4]);
+ chip->VBLANK = &(chip->PGRAPH[0x0100/4]);
+ chip->VBlankBit = 0x00000100;
+ chip->MaxVClockFreqKHz = 230000;
+ chip->LockUnlockIO = 0x3C4;
+ chip->LockUnlockIndex = 0x06;
+ /*
+ * Set chip functions.
+ */
+ chip->Busy = nv3Busy;
+ chip->ShowHideCursor = ShowHideCursor;
+ chip->CalcStateExt = CalcStateExt;
+ chip->LoadStateExt = LoadStateExt;
+ chip->UnloadStateExt = UnloadStateExt;
+ chip->SetStartAddress = SetStartAddress;
+ chip->SetSurfaces2D = nv3SetSurfaces2D;
+ chip->SetSurfaces3D = nv3SetSurfaces3D;
+}
+void nv4GetConfig
+(
+ RIVA_HW_INST *chip
+)
+{
+ /*
+ * Fill in chip configuration.
+ */
+ switch (chip->PFB[0x00000000/4] & 0x00000003)
+ {
+ case 0:
+ chip->RamAmountKBytes = 1024 * 32 - 128;
+ break;
+ case 1:
+ chip->RamAmountKBytes = 1024 * 4 - 128;
+ break;
+ case 2:
+ chip->RamAmountKBytes = 1024 * 8 - 128;
+ break;
+ case 3:
+ default:
+ chip->RamAmountKBytes = 1024 * 16 - 128;
+ break;
+ }
+ switch ((chip->PFB[0x00000000/4] >> 3) & 0x00000003)
+ {
+ case 3:
+ chip->RamBandwidthKBytesPerSec = 800000;
+ break;
+ default:
+ chip->RamBandwidthKBytesPerSec = 1000000;
+ break;
+ }
+ chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500;
+ chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]);
+ chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]);
+ chip->VBLANKENABLE = &(chip->PCRTC[0x0140/4]);
+ chip->VBLANK = &(chip->PCRTC[0x0100/4]);
+ chip->VBlankBit = 0x00000001;
+ chip->MaxVClockFreqKHz = 250000;
+ chip->LockUnlockIO = 0x3D4;
+ chip->LockUnlockIndex = 0x1F;
+ /*
+ * Set chip functions.
+ */
+ chip->Busy = nv4Busy;
+ chip->ShowHideCursor = ShowHideCursor;
+ chip->CalcStateExt = CalcStateExt;
+ chip->LoadStateExt = LoadStateExt;
+ chip->UnloadStateExt = UnloadStateExt;
+ chip->SetStartAddress = SetStartAddress;
+ chip->SetSurfaces2D = nv4SetSurfaces2D;
+ chip->SetSurfaces3D = nv4SetSurfaces3D;
+}
+int RivaGetConfig
+(
+ RIVA_HW_INST *chip
+)
+{
+ /*
+ * Save this so future SW know whats it's dealing with.
+ */
+ chip->Version = RIVA_SW_VERSION;
+ /*
+ * Chip specific configuration.
+ */
+ switch (chip->Architecture)
+ {
+ case 3:
+ nv3GetConfig(chip);
+ break;
+ case 4:
+ nv4GetConfig(chip);
+ break;
+ default:
+ return (-1);
+ }
+ /*
+ * Fill in FIFO pointers.
+ */
+ chip->Rop = (RivaRop *)&(chip->FIFO[0x00000000/4]);
+ chip->Clip = (RivaClip *)&(chip->FIFO[0x00002000/4]);
+ chip->Patt = (RivaPattern *)&(chip->FIFO[0x00004000/4]);
+ chip->Pixmap = (RivaPixmap *)&(chip->FIFO[0x00006000/4]);
+ chip->Blt = (RivaScreenBlt *)&(chip->FIFO[0x00008000/4]);
+ chip->Bitmap = (RivaBitmap *)&(chip->FIFO[0x0000A000/4]);
+ chip->Tri03 = (RivaTexturedTriangle03 *)&(chip->FIFO[0x0000E000/4]);
+ return (0);
+}
+
diff --git a/nvidia/riva_hw.h b/nvidia/riva_hw.h
new file mode 100644
index 0000000..f06c7d5
--- /dev/null
+++ b/nvidia/riva_hw.h
@@ -0,0 +1,336 @@
+/***************************************************************************\
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
+|* international laws. Users and possessors of this source code are *|
+|* hereby granted a nonexclusive, royalty-free copyright license to *|
+|* use this code in individual and commercial software. *|
+|* *|
+|* Any use of this source code must include, in the user documenta- *|
+|* tion and internal comments to the code, notices to the end user *|
+|* as follows: *|
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
+|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
+|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
+|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
+|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
+|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
+|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
+|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
+|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
+|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
+|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
+|* *|
+|* U.S. Government End Users. This source code is a "commercial *|
+|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
+|* consisting of "commercial computer software" and "commercial *|
+|* computer software documentation," as such terms are used in *|
+|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
+|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
+|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
+|* all U.S. Government End Users acquire the source code with only *|
+|* those rights set forth herein. *|
+|* *|
+\***************************************************************************/
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/riva_hw.h,v 1.1.2.2 1998/12/22 16:33:19 hohndel Exp $ */
+#ifndef __RIVA_HW_H__
+#define __RIVA_HW_H__
+#define RIVA_SW_VERSION 0x00010000
+
+/***************************************************************************\
+* *
+* FIFO registers. *
+* *
+\***************************************************************************/
+
+/*
+ * Raster OPeration. Windows style ROP3.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BB];
+ unsigned Rop3;
+} RivaRop;
+/*
+ * 8X8 Monochrome pattern.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BD];
+ unsigned Shape;
+ unsigned reserved03[0x001];
+ unsigned Color0;
+ unsigned Color1;
+ unsigned Monochrome[2];
+} RivaPattern;
+/*
+ * Scissor clip rectangle.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BB];
+ unsigned TopLeft;
+ unsigned WidthHeight;
+} RivaClip;
+/*
+ * 2D filled rectangle.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop[1];
+ unsigned reserved01[0x0BC];
+ unsigned Color;
+ unsigned reserved03[0x03E];
+ unsigned TopLeft;
+ unsigned WidthHeight;
+} RivaRectangle;
+/*
+ * 2D screen-screen BLT.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BB];
+ unsigned TopLeftSrc;
+ unsigned TopLeftDst;
+ unsigned WidthHeight;
+} RivaScreenBlt;
+/*
+ * 2D pixel BLT.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop[1];
+ unsigned reserved01[0x0BC];
+ unsigned TopLeft;
+ unsigned WidthHeight;
+ unsigned WidthHeightIn;
+ unsigned reserved02[0x03C];
+ unsigned Pixels;
+} RivaPixmap;
+/*
+ * Filled rectangle combined with monochrome expand. Useful for glyphs.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BB];
+ unsigned reserved03[(0x040)-1];
+ unsigned Color1A;
+ struct
+ {
+ unsigned TopLeft;
+ unsigned WidthHeight;
+ } UnclippedRectangle[64];
+ unsigned reserved04[(0x080)-3];
+ struct
+ {
+ unsigned TopLeft;
+ unsigned BottomRight;
+ } ClipB;
+ unsigned Color1B;
+ struct
+ {
+ unsigned TopLeft;
+ unsigned BottomRight;
+ } ClippedRectangle[64];
+ unsigned reserved05[(0x080)-5];
+ struct
+ {
+ unsigned TopLeft;
+ unsigned BottomRight;
+ } ClipC;
+ unsigned Color1C;
+ unsigned WidthHeightC;
+ unsigned PointC;
+ unsigned MonochromeData1C;
+ unsigned reserved06[(0x080)+121];
+ struct
+ {
+ unsigned TopLeft;
+ unsigned BottomRight;
+ } ClipD;
+ unsigned Color1D;
+ unsigned WidthHeightInD;
+ unsigned WidthHeightOutD;
+ unsigned PointD;
+ unsigned MonochromeData1D;
+ unsigned reserved07[(0x080)+120];
+ struct
+ {
+ unsigned TopLeft;
+ unsigned BottomRight;
+ } ClipE;
+ unsigned Color0E;
+ unsigned Color1E;
+ unsigned WidthHeightInE;
+ unsigned WidthHeightOutE;
+ unsigned PointE;
+ unsigned MonochromeData01E;
+} RivaBitmap;
+/*
+ * 3D textured, Z buffered triangle.
+ */
+typedef volatile struct
+{
+ unsigned reserved00[4];
+ unsigned short FifoFree;
+ unsigned short Nop;
+ unsigned reserved01[0x0BC];
+ unsigned TextureOffset;
+ unsigned TextureFormat;
+ unsigned TextureFilter;
+ unsigned FogColor;
+ unsigned Control;
+ unsigned AlphaTest;
+ unsigned reserved02[0x339];
+ unsigned FogAndIndex;
+ unsigned Color;
+ float ScreenX;
+ float ScreenY;
+ float ScreenZ;
+ float EyeM;
+ float TextureS;
+ float TextureT;
+} RivaTexturedTriangle03;
+
+/***************************************************************************\
+* *
+* Virtualized RIVA H/W interface. *
+* *
+\***************************************************************************/
+
+struct _riva_hw_inst;
+struct _riva_hw_state;
+/*
+ * Virtialized chip interface. Makes RIVA 128 and TNT look alike.
+ */
+typedef struct _riva_hw_inst
+{
+ /*
+ * Chip specific settings.
+ */
+ unsigned Architecture;
+ unsigned Version;
+ unsigned CrystalFreqKHz;
+ unsigned RamAmountKBytes;
+ unsigned MaxVClockFreqKHz;
+ unsigned RamBandwidthKBytesPerSec;
+ unsigned EnableIRQ;
+ unsigned IO;
+ unsigned LockUnlockIO;
+ unsigned LockUnlockIndex;
+ unsigned VBlankBit;
+ unsigned FifoFreeCount;
+ /*
+ * Non-FIFO registers.
+ */
+ volatile unsigned *PCRTC;
+ volatile unsigned *PRAMDAC;
+ volatile unsigned *PFB;
+ volatile unsigned *PFIFO;
+ volatile unsigned *PGRAPH;
+ volatile unsigned *PEXTDEV;
+ volatile unsigned *PTIMER;
+ volatile unsigned *PMC;
+ volatile unsigned *PRAMIN;
+ volatile unsigned *FIFO;
+ volatile unsigned *CURSOR;
+ volatile unsigned *CURSORPOS;
+ volatile unsigned *VBLANKENABLE;
+ volatile unsigned *VBLANK;
+ /*
+ * Common chip functions.
+ */
+ int (*Busy)(struct _riva_hw_inst *);
+ void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int,int,int,int,int,int,int,int,int);
+ void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *, int all);
+ void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
+ void (*SetStartAddress)(struct _riva_hw_inst *,unsigned);
+ void (*SetSurfaces2D)(struct _riva_hw_inst *,unsigned,unsigned);
+ void (*SetSurfaces3D)(struct _riva_hw_inst *,unsigned,unsigned);
+ int (*ShowHideCursor)(struct _riva_hw_inst *,int);
+ /*
+ * Current extended mode settings.
+ */
+ struct _riva_hw_state *CurrentState;
+ /*
+ * FIFO registers.
+ */
+ RivaRop *Rop;
+ RivaPattern *Patt;
+ RivaClip *Clip;
+ RivaPixmap *Pixmap;
+ RivaScreenBlt *Blt;
+ RivaBitmap *Bitmap;
+ RivaTexturedTriangle03 *Tri03;
+} RIVA_HW_INST;
+/*
+ * Extended mode state information.
+ */
+typedef struct _riva_hw_state
+{
+ unsigned bpp;
+ unsigned width;
+ unsigned height;
+ unsigned repaint0;
+ unsigned repaint1;
+ unsigned screen;
+ unsigned pixel;
+ unsigned horiz;
+ unsigned arbitration0;
+ unsigned arbitration1;
+ unsigned vpll;
+ unsigned pllsel;
+ unsigned general;
+ unsigned config;
+ unsigned cursor0;
+ unsigned cursor1;
+ unsigned cursor2;
+ unsigned offset0;
+ unsigned offset1;
+ unsigned offset2;
+ unsigned offset3;
+ unsigned pitch0;
+ unsigned pitch1;
+ unsigned pitch2;
+ unsigned pitch3;
+} RIVA_HW_STATE;
+/*
+ * External routines.
+ */
+int RivaGetConfig(RIVA_HW_INST *);
+/*
+ * FIFO Free Count. Should attempt to yield processor if RIVA is busy.
+ */
+#define RIVA_FIFO_FREE(hwinst,hwptr,cnt) \
+{ \
+while ((hwinst).FifoFreeCount < (cnt)) \
+{ \
+ (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2; \
+} \
+(hwinst).FifoFreeCount -= (cnt); \
+}
+#endif /* __RIVA_HW_H__ */
+
diff --git a/nvidia/riva_tbl.h b/nvidia/riva_tbl.h
new file mode 100644
index 0000000..c03e7ac
--- /dev/null
+++ b/nvidia/riva_tbl.h
@@ -0,0 +1,395 @@
+ /***************************************************************************\
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
+|* international laws. Users and possessors of this source code are *|
+|* hereby granted a nonexclusive, royalty-free copyright license to *|
+|* use this code in individual and commercial software. *|
+|* *|
+|* Any use of this source code must include, in the user documenta- *|
+|* tion and internal comments to the code, notices to the end user *|
+|* as follows: *|
+|* *|
+|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
+|* *|
+|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
+|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
+|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
+|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
+|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
+|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
+|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
+|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
+|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
+|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
+|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
+|* *|
+|* U.S. Government End Users. This source code is a "commercial *|
+|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
+|* consisting of "commercial computer software" and "commercial *|
+|* computer software documentation," as such terms are used in *|
+|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
+|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
+|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
+|* all U.S. Government End Users acquire the source code with only *|
+|* those rights set forth herein. *|
+|* *|
+ \***************************************************************************/
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/riva_tbl.h,v 1.1.2.2 1998/12/22 16:33:20 hohndel Exp $ */
+/*
+ * RIVA Fixed Functionality Init Tables.
+ */
+static unsigned RivaTablePMC[][2] =
+{
+ {0x00000050, 0x00000000},
+ {0x00000080, 0xFFFF00FF},
+ {0x00000080, 0xFFFFFFFF}
+};
+static unsigned RivaTablePTIMER[][2] =
+{
+ {0x00000080, 0x00000008},
+ {0x00000084, 0x00000003},
+ {0x00000050, 0x00000000},
+ {0x00000040, 0xFFFFFFFF}
+};
+static unsigned RivaTableFIFO[][2] =
+{
+ {0x00000000, 0x80000000},
+ {0x00000800, 0x80000001},
+ {0x00001000, 0x80000002},
+ {0x00001800, 0x80000010},
+ {0x00002000, 0x80000011},
+ {0x00002800, 0x80000012},
+ {0x00003800, 0x80000013}
+};
+static unsigned nv3TablePFIFO[][2] =
+{
+ {0x00000140, 0x00000000},
+ {0x00000480, 0x00000000},
+ {0x00000490, 0x00000000},
+ {0x00000494, 0x00000000},
+ {0x00000481, 0x00000000},
+ {0x00000084, 0x00000000},
+ {0x00000086, 0x00002000},
+ {0x00000085, 0x00002200},
+ {0x00000484, 0x00000000},
+ {0x0000049C, 0x00000000},
+ {0x00000104, 0x00000000},
+ {0x00000108, 0x00000000},
+ {0x00000100, 0x00000000},
+ {0x000004A0, 0x00000000},
+ {0x000004A4, 0x00000000},
+ {0x000004A8, 0x00000000},
+ {0x000004AC, 0x00000000},
+ {0x000004B0, 0x00000000},
+ {0x000004B4, 0x00000000},
+ {0x000004B8, 0x00000000},
+ {0x000004BC, 0x00000000},
+ {0x00000050, 0x00000000},
+ {0x00000040, 0xFFFFFFFF},
+ {0x00000480, 0x00000001},
+ {0x00000490, 0x00000001},
+ {0x00000140, 0x00000001}
+};
+static unsigned nv3TablePGRAPH[][2] =
+{
+ {0x00000020, 0x1230001F},
+ {0x00000021, 0x10113000},
+ {0x00000022, 0x1131F101},
+ {0x00000023, 0x0100F531},
+ {0x00000060, 0x00000000},
+ {0x00000065, 0x00000000},
+ {0x00000068, 0x00000000},
+ {0x00000069, 0x00000000},
+ {0x0000006A, 0x00000000},
+ {0x0000006B, 0x00000000},
+ {0x0000006C, 0x00000000},
+ {0x0000006D, 0x00000000},
+ {0x0000006E, 0x00000000},
+ {0x0000006F, 0x00000000},
+ {0x000001A8, 0x00000000},
+ {0x00000440, 0xFFFFFFFF},
+ {0x00000480, 0x00000001},
+ {0x000001A0, 0x00000000},
+ {0x000001A2, 0x00000000},
+ {0x0000018A, 0xFFFFFFFF},
+ {0x00000190, 0x00000000},
+ {0x00000142, 0x00000000},
+ {0x00000154, 0x00000000},
+ {0x00000155, 0xFFFFFFFF},
+ {0x00000156, 0x00000000},
+ {0x00000157, 0xFFFFFFFF},
+ {0x00000064, 0x10010002},
+ {0x00000050, 0x00000000},
+ {0x00000051, 0x00000000},
+ {0x00000040, 0xFFFFFFFF},
+ {0x00000041, 0xFFFFFFFF},
+ {0x00000440, 0xFFFFFFFF},
+ {0x000001A9, 0x00000001}
+};
+static unsigned nv3TablePGRAPH_8BPP[][2] =
+{
+ {0x000001AA, 0x00001111}
+};
+static unsigned nv3TablePGRAPH_15BPP[][2] =
+{
+ {0x000001AA, 0x00002222}
+};
+static unsigned nv3TablePGRAPH_32BPP[][2] =
+{
+ {0x000001AA, 0x00003333}
+};
+static unsigned nv3TablePRAMIN[][2] =
+{
+ {0x00000500, 0x00010000},
+ {0x00000501, 0x007FFFFF},
+ {0x00000200, 0x80000000},
+ {0x00000201, 0x00C20341},
+ {0x00000204, 0x80000001},
+ {0x00000205, 0x00C50342},
+ {0x00000208, 0x80000002},
+ {0x00000209, 0x00C60343},
+ {0x00000240, 0x80000010},
+ {0x00000241, 0x00D10344},
+ {0x00000244, 0x80000011},
+ {0x00000245, 0x00D00345},
+ {0x00000248, 0x80000012},
+ {0x00000249, 0x00CC0346},
+ {0x0000024C, 0x80000013},
+ {0x0000024D, 0x00D70347},
+ {0x00000D05, 0x00000000},
+ {0x00000D06, 0x00000000},
+ {0x00000D07, 0x00000000},
+ {0x00000D09, 0x00000000},
+ {0x00000D0A, 0x00000000},
+ {0x00000D0B, 0x00000000},
+ {0x00000D0D, 0x00000000},
+ {0x00000D0E, 0x00000000},
+ {0x00000D0F, 0x00000000},
+ {0x00000D11, 0x00000000},
+ {0x00000D12, 0x00000000},
+ {0x00000D13, 0x00000000},
+ {0x00000D15, 0x00000000},
+ {0x00000D16, 0x00000000},
+ {0x00000D17, 0x00000000},
+ {0x00000D19, 0x00000000},
+ {0x00000D1A, 0x00000000},
+ {0x00000D1B, 0x00000000},
+ {0x00000D1D, 0x00000140},
+ {0x00000D1E, 0x00000000},
+ {0x00000D1F, 0x00000000}
+};
+static unsigned nv3TablePRAMIN_8BPP[][2] =
+{
+ {0x00000D04, 0x10110203},
+ {0x00000D08, 0x10110203},
+ {0x00000D0C, 0x10110203},
+ {0x00000D10, 0x10118203},
+ {0x00000D14, 0x10110203},
+ {0x00000D18, 0x10110203},
+ {0x00000D1C, 0x10419208}
+};
+static unsigned nv3TablePRAMIN_15BPP[][2] =
+{
+ {0x00000D04, 0x10110200},
+ {0x00000D08, 0x10110200},
+ {0x00000D0C, 0x10110200},
+ {0x00000D10, 0x10118200},
+ {0x00000D14, 0x10110200},
+ {0x00000D18, 0x10110200},
+ {0x00000D1C, 0x10419208}
+};
+static unsigned nv3TablePRAMIN_32BPP[][2] =
+{
+ {0x00000D04, 0x10110201},
+ {0x00000D08, 0x10110201},
+ {0x00000D0C, 0x10110201},
+ {0x00000D10, 0x10118201},
+ {0x00000D14, 0x10110201},
+ {0x00000D18, 0x10110201},
+ {0x00000D1C, 0x10419208}
+};
+static unsigned nv4TablePFIFO[][2] =
+{
+ {0x00000140, 0x00000000},
+ {0x00000480, 0x00000000},
+ {0x00000494, 0x00000000},
+ {0x00000400, 0x00000000},
+ {0x00000414, 0x00000000},
+ {0x00000084, 0x03000100},
+ {0x00000085, 0x00000110},
+ {0x00000086, 0x00000112},
+ {0x00000143, 0x0000FFFF},
+ {0x00000496, 0x0000FFFF},
+ {0x00000050, 0x00000000},
+ {0x00000040, 0xFFFFFFFF},
+ {0x00000415, 0x00000001},
+ {0x00000480, 0x00000001},
+ {0x00000494, 0x00000001},
+ {0x00000495, 0x00000001},
+ {0x00000140, 0x00000001}
+};
+static unsigned nv4TablePGRAPH[][2] =
+{
+ {0x00000020, 0x1231C001},
+ {0x00000021, 0x72111101},
+ {0x00000022, 0x11D5F071},
+ {0x00000023, 0x10D4FF31},
+ {0x00000060, 0x00000000},
+ {0x00000068, 0x00000000},
+ {0x00000070, 0x00000000},
+ {0x00000078, 0x00000000},
+ {0x00000061, 0x00000000},
+ {0x00000069, 0x00000000},
+ {0x00000071, 0x00000000},
+ {0x00000079, 0x00000000},
+ {0x00000062, 0x00000000},
+ {0x0000006A, 0x00000000},
+ {0x00000072, 0x00000000},
+ {0x0000007A, 0x00000000},
+ {0x00000063, 0x00000000},
+ {0x0000006B, 0x00000000},
+ {0x00000073, 0x00000000},
+ {0x0000007B, 0x00000000},
+ {0x00000064, 0x00000000},
+ {0x0000006C, 0x00000000},
+ {0x00000074, 0x00000000},
+ {0x0000007C, 0x00000000},
+ {0x00000065, 0x00000000},
+ {0x0000006D, 0x00000000},
+ {0x00000075, 0x00000000},
+ {0x0000007D, 0x00000000},
+ {0x00000066, 0x00000000},
+ {0x0000006E, 0x00000000},
+ {0x00000076, 0x00000000},
+ {0x0000007E, 0x00000000},
+ {0x00000067, 0x00000000},
+ {0x0000006F, 0x00000000},
+ {0x00000077, 0x00000000},
+ {0x0000007F, 0x00000000},
+ {0x00000058, 0x00000000},
+ {0x00000059, 0x00000000},
+ {0x0000005A, 0x00000000},
+ {0x0000005B, 0x00000000},
+ {0x00000196, 0x00000000},
+ {0x000001A1, 0x00FFFFFF},
+ {0x00000197, 0x00000000},
+ {0x000001A2, 0x00FFFFFF},
+ {0x00000198, 0x00000000},
+ {0x000001A3, 0x00FFFFFF},
+ {0x00000199, 0x00000000},
+ {0x000001A4, 0x00FFFFFF},
+ {0x00000050, 0x00000000},
+ {0x00000040, 0xFFFFFFFF},
+ {0x0000005C, 0x10010100},
+ {0x000001C8, 0x00000001}
+};
+static unsigned nv4TablePGRAPH_8BPP[][2] =
+{
+ {0x000001C4, 0xFFFFFFFF},
+ {0x000001C9, 0x00111111},
+ {0x00000186, 0x00001010},
+ {0x0000020C, 0x01010101}
+};
+static unsigned nv4TablePGRAPH_15BPP[][2] =
+{
+ {0x000001C4, 0xFFFFFFFF},
+ {0x000001C9, 0x00226222},
+ {0x00000186, 0x00002071},
+ {0x0000020C, 0x09090909}
+};
+static unsigned nv4TablePGRAPH_16BPP[][2] =
+{
+ {0x000001C4, 0xFFFFFFFF},
+ {0x000001C9, 0x00556555},
+ {0x00000186, 0x000050C2},
+ {0x0000020C, 0x0C0C0C0C}
+};
+static unsigned nv4TablePGRAPH_32BPP[][2] =
+{
+ {0x000001C4, 0xFFFFFFFF},
+ {0x000001C9, 0x0077D777},
+ {0x00000186, 0x000070E5},
+ {0x0000020C, 0x07070707}
+};
+static unsigned nv4TablePRAMIN[][2] =
+{
+ {0x00000000, 0x80000010},
+ {0x00000001, 0x80011145},
+ {0x00000002, 0x80000011},
+ {0x00000003, 0x80011146},
+ {0x00000004, 0x80000012},
+ {0x00000005, 0x80011147},
+ {0x00000006, 0x80000013},
+ {0x00000007, 0x80011148},
+ {0x00000020, 0x80000000},
+ {0x00000021, 0x80011142},
+ {0x00000022, 0x80000001},
+ {0x00000023, 0x80011143},
+ {0x00000024, 0x80000002},
+ {0x00000025, 0x80011144},
+ {0x00000500, 0x00003000},
+ {0x00000501, 0x02FFFFFF},
+ {0x00000502, 0x00000002},
+ {0x00000503, 0x00000002},
+ {0x00000508, 0x01008043},
+ {0x0000050A, 0x00000000},
+ {0x0000050B, 0x00000000},
+ {0x0000050C, 0x01008019},
+ {0x0000050E, 0x00000000},
+ {0x0000050F, 0x00000000},
+ {0x00000510, 0x01008018},
+ {0x00000512, 0x00000000},
+ {0x00000513, 0x00000000},
+ {0x00000514, 0x0100A033},
+ {0x00000516, 0x00000000},
+ {0x00000517, 0x00000000},
+ {0x00000518, 0x0100805F},
+ {0x0000051A, 0x00000000},
+ {0x0000051B, 0x00000000},
+ {0x0000051C, 0x0100804B},
+ {0x0000051E, 0x00000000},
+ {0x0000051F, 0x00000000},
+ {0x00000520, 0x0100A048},
+ {0x00000521, 0x00000D01},
+ {0x00000522, 0x11401140},
+ {0x00000523, 0x00000000}
+};
+static unsigned nv4TablePRAMIN_8BPP[][2] =
+{
+ {0x00000509, 0x00000301},
+ {0x0000050D, 0x00000301},
+ {0x00000511, 0x00000301},
+ {0x00000515, 0x00000301},
+ {0x00000519, 0x00000301},
+ {0x0000051D, 0x00000301}
+};
+static unsigned nv4TablePRAMIN_15BPP[][2] =
+{
+ {0x00000509, 0x00000901},
+ {0x0000050D, 0x00000901},
+ {0x00000511, 0x00000901},
+ {0x00000515, 0x00000901},
+ {0x00000519, 0x00000901},
+ {0x0000051D, 0x00000901}
+};
+static unsigned nv4TablePRAMIN_16BPP[][2] =
+{
+ {0x00000509, 0x00000C01},
+ {0x0000050D, 0x00000C01},
+ {0x00000511, 0x00000C01},
+ {0x00000515, 0x00000C01},
+ {0x00000519, 0x00000C01},
+ {0x0000051D, 0x00000C01}
+};
+static unsigned nv4TablePRAMIN_32BPP[][2] =
+{
+ {0x00000509, 0x00000E01},
+ {0x0000050D, 0x00000E01},
+ {0x00000511, 0x00000E01},
+ {0x00000515, 0x00000E01},
+ {0x00000519, 0x00000E01},
+ {0x0000051D, 0x00000E01}
+};
+
diff --git a/paradise/driver.c b/paradise/driver.c
new file mode 100644
index 0000000..ee7b0b3
--- /dev/null
+++ b/paradise/driver.c
@@ -0,0 +1,673 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Paradise driver (based on the Allegro Paradise code).
+ *
+ * By Francois Charton and Shawn Hargreaves.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+// #define NO_HWPTR
+
+
+#include
+
+#include "vbeaf.h"
+
+
+
+/* chipset information */
+#define PVGA1 1
+#define WD90C 2
+
+int paradise_type = 0;
+
+
+
+/* driver function prototypes */
+void CirrusSetBank32();
+void CirrusSetBank32End();
+void CirrusSetBank(AF_DRIVER *af, long bank);
+void ParadiseSetBank32();
+void ParadiseSetBank32End();
+void ParadiseSetBank(AF_DRIVER *af, long bank);
+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);
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+} VIDEO_MODE;
+
+
+VIDEO_MODE mode_list[] =
+{
+ { 640, 400, 8, 0x5E },
+ { 640, 480, 8, 0x5F },
+ { 800, 600, 8, 0x5C }
+};
+
+
+#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_modes[NUM_MODES+1] = { 1, 2, 3, -1 };
+
+
+
+/* detect:
+ * Detects the presence of a Paradise card.
+ */
+char *detect(unsigned long *vidmem)
+{
+ char *name = NULL;
+ RM_REGS r;
+ int old, old2;
+
+ old = read_vga_register(0x3CE, 0xF);
+ write_vga_register(0x3CE, 0xF, old | 0x17); /* lock extended registers */
+
+ if (test_vga_register(0x3CE, 0x9, 0x7F)) { /* not a Paradise card! */
+ write_vga_register(0x3CE, 0xF, old);
+ return NULL;
+ }
+
+ alter_vga_register(0x3CE, 0xF, 0x17, 5); /* unlock extended regs */
+
+ if (!test_vga_register(0x3CE, 0x9, 0x7F)) { /* not a Paradise card! */
+ write_vga_register(0x3CE, 0xF, old);
+ return NULL;
+ }
+
+ old2 = read_vga_register(0x3D4, 0x29);
+ alter_vga_register(0x3D4, 0x29, 0x8F, 0x85);
+
+ if (!test_vga_register(0x3D4, 0x2B, 0xFF)) {
+ paradise_type = PVGA1;
+ name = "PVGA1";
+ goto end;
+ }
+
+ write_vga_register(0x3C4, 0x06, 0x48);
+
+ if (!test_vga_register(0x3C4, 0x7, 0xF0)) {
+ paradise_type = PVGA1;
+ name = "WD90C0x";
+ goto end;
+ }
+
+ if (!test_vga_register(0x3C4, 0x10, 0xFF)) {
+ paradise_type = PVGA1;
+ name = "WD90C2x";
+ write_vga_register(0x3D4, 0x34, 0xA6);
+ if (read_vga_register(0x3D4, 0x32) & 0x20)
+ write_vga_register(0x3D4, 0x34, 0);
+ goto end;
+ }
+
+ paradise_type = WD90C;
+ name = "WD90C1x or 24+";
+
+ end:
+
+ write_vga_register(0x3D4, 0x29, old2);
+ write_vga_register(0x3CE, 0xF, old);
+
+ r.x.ax = 0x007F;
+ r.h.bh = 0x02;
+ rm_int(0x10, &r);
+ *vidmem = r.h.ch * 64;
+
+ return name;
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ char *name;
+ int i;
+
+ name = detect(&af->TotalMemory);
+
+ if (!name)
+ return 1;
+
+ i = 0;
+ while (af->OemVendorName[i])
+ i++;
+
+ af->OemVendorName[i++] = ',';
+ af->OemVendorName[i++] = ' ';
+
+ while (*name)
+ af->OemVendorName[i++] = *(name++);
+
+ af->OemVendorName[i] = 0;
+
+ af->AvailableModes = available_modes;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ if (paradise_type == PVGA1) {
+ af->SetBank32 = CirrusSetBank32;
+ af->SetBank32Len = (long)CirrusSetBank32End - (long)CirrusSetBank32;
+ af->SetBank = CirrusSetBank;
+ }
+ else {
+ af->SetBank32 = ParadiseSetBank32;
+ af->SetBank32Len = (long)ParadiseSetBank32End - (long)ParadiseSetBank32;
+ af->SetBank = ParadiseSetBank;
+ }
+
+ 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;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ long available_vram;
+ long used_vram;
+ int width;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo, linear framebuffer, or noclear */
+ if (mode & 0xC400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > NUM_MODES))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ /* call BIOS to set the mode */
+ r.x.ax = info->num;
+ rm_int(0x10, &r);
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX > info->w) {
+ if (virtualX > 1024)
+ return -1;
+
+ *bytesPerLine = ((virtualX*BYTES_PER_PIXEL(info->bpp))+15)&0xFFF0;
+
+ width = read_vga_register(0x3D4, 0x13);
+ write_vga_register(0x3D4, 0x13, (width * (*bytesPerLine)) / (info->w*BYTES_PER_PIXEL(info->bpp)));
+ }
+ else
+ *bytesPerLine = info->w*BYTES_PER_PIXEL(info->bpp);
+
+ /* set up some hardware registers */
+ if (paradise_type != PVGA1) {
+ write_vga_register(0x3C4, 0x06, 0x48);
+
+ alter_vga_register(0x3C4, 0x11, 0x80, 0x80);
+ alter_vga_register(0x3CE, 0x0B, 0x80, 0x80);
+
+ write_vga_register(0x3C4, 0x06, 0x00);
+ }
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* write high bits to Paradise register 3CE indx 0xD, bits 3-4 */
+ alter_vga_register(0x3CE, 0x0D, 0x18, a>>15);
+
+ /* write to normal VGA address registers */
+ write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
+ write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
+
+ asm volatile ("sti");
+
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i
+
+#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 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 WaitTillIdle(AF_DRIVER *af);
+
+
+
+#define S86c911A 0x82
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+int af_chipid;
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+ int bpl;
+ int redsize;
+ int redpos;
+ int greensize;
+ int greenpos;
+ int bluesize;
+ int bluepos;
+ int rsvdsize;
+ int rsvdpos;
+} VIDEO_MODE;
+
+
+VIDEO_MODE mode_list[] =
+{
+ { 640, 400, 8, 0x100, 640 },
+ { 640, 480, 8, 0x101, 640 },
+ { 800, 600, 8, 0x103, 800 },
+ { 1024, 768, 8, 0x105, 1024 },
+ { 1280, 1024, 8, 0x107, 1280 },
+ { 640, 480, 15, 0x110, 1280,5,10,5,5,5,0,0,0},
+ { 800, 600, 15, 0x113, 1600,5,10,5,5,5,0,0,0},
+ { 1024, 768, 15, 0x116, 2048,5,10,5,5,5,0,0,0},
+ { 1280, 1024, 15, 0x119, 2560,5,10,5,5,5,0,0,0},
+ { 640, 480, 16, 0x111, 1024,5,11,6,5,5,0,0,0},
+ { 800, 600, 16, 0x114, 1600,5,11,6,5,5,0,0,0},
+ { 1024, 768, 16, 0x117, 2048,5,11,6,5,5,0,0,0},
+ { 1280, 1024, 16, 0x11A, 2560,5,11,6,5,5,0,0,0},
+ { 640, 480, 32, 0x112, 2048,8,16,8,8,8,0,0,0},
+ { 800, 600, 32, 0x115, 3200,8,16,8,8,8,0,0,0},
+ { 1024, 768, 32, 0x118, 4096,8,16,8,8,8,0,0,0}
+};
+
+
+#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_modes[NUM_MODES+1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, -1 };
+
+
+
+void mod_vga_register_bits ( int reg, int m, int mask, int nwv )
+{
+ int temp = (read_vga_register(reg,m) & (!mask))+(nwv & mask);
+ write_vga_register(reg, m, temp);
+};
+
+void set_vga_register_bits ( int reg, int m, int b )
+{
+ int x = read_vga_register(reg,m);
+ write_vga_register(reg, m, x | b);
+};
+
+void clear_vga_register_bits ( int reg, int m, int b )
+{
+ int x = read_vga_register(reg,m);
+ write_vga_register(reg, m, x & (!b));
+};
+
+void accelIT ( void )
+{
+ write_vga_register(0x3D4, 0x38, 0x48);
+ write_vga_register(0x3D4, 0x39, 0xA5);
+ clear_vga_register_bits(0x3D4, 0x58, 0x14);
+ mod_vga_register_bits(0x3D4, 0x40, 9, 1);
+ clear_vga_register_bits(0x3D4, 0x53, 0xF);
+ write_vga_register(0x3D4, 0x54, 0xA0);
+ outportw(0xBEE8, 0xE000);
+ outportw(0xAAE8, 0xFFFF);
+ outportw(0xAEE8, 0xFFFF);
+ if ( af_bpp >= 24 ) {
+ outportw(0xBEE8, 0xE010);
+ outportw(0xAAE8, 0xFFFF);
+ outportw(0xAEE8, 0xFFFF);
+ };
+};
+
+
+void unaccelIT ( void )
+{
+ write_vga_register(0x3D4, 0x38, 0x48); /* unlock cr38 */
+ write_vga_register(0x3D4, 0x39, 0xA5); /* unlock cr39 */
+ if ( read_vga_register(0x3D4, 0x40) )
+ do ; while ( inportw(0x9AE8) & 0x200 ); /* if graph. procesor is busy (9bit)*/
+ clear_vga_register_bits(0x3D4, 0x40, 1); /* not enhanced reg access */
+ set_vga_register_bits(0x3D4, 0x40, 8); /* enable fast write buffer (3bit) */
+};
+
+int readchipid ( void )
+{
+ return read_vga_register(0x3d4, 0x30);
+};
+
+/* detect:
+ * Detects the presence of a S3 card.
+ */
+int detect()
+{
+ int old;
+ int result = FALSE;
+
+ old = read_vga_register(0x3D4, 0x38);
+ write_vga_register(0x3D4, 0x38, 0); /* disable ext. */
+ if (!test_vga_register(0x3D4, 0x35, 0xF)) { /* test */
+ write_vga_register(0x3D4, 0x38, 0x48); /* enable ext. */
+ if (test_vga_register(0x3D4, 0x35, 0xF)) /* test again */
+ result = TRUE; /* found it */
+ af_chipid = readchipid();
+ }
+
+ write_vga_register(0x3D4, 0x38, old);
+
+ return result;
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ int vram_size;
+
+ if (!detect())
+ return 1;
+
+ if (get_vesa_info(&vram_size, NULL, NULL) != 0)
+ return -1;
+
+ af->AvailableModes = available_modes;
+
+ af->TotalMemory = vram_size/1024;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveAccel2D |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ 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->Set8x8MonoPattern = NULL;
+ af->DrawScan = NULL;
+ af->DrawPattScan = NULL;
+ af->DrawRect = NULL;
+ af->DrawPattRect = NULL;
+ af->DrawLine = NULL;
+ af->DrawTrap = NULL;
+ af->PutMonoImage = NULL;
+ af->BitBlt = BitBlt;
+ af->BitBltSys = NULL;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ 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 = modeInfo->BytesPerScanLine;
+ 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;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ int noclear = ((mode & 0x8000) != 0);
+ long available_vram;
+ long used_vram;
+ int pitch;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo or linear framebuffer */
+ if (mode & 0x4400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > NUM_MODES))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ /* call VESA to set the mode */
+ r.x.ax = 0x4F02;
+ r.x.bx = info->num;
+ if (noclear)
+ r.x.bx |= 0x8000;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+
+
+ if (virtualX*BYTES_PER_PIXEL(info->bpp) > info->bpl) {
+ r.x.ax = 0x4F06;
+ r.x.bx = 0;
+ r.x.cx = virtualX;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+ *bytesPerLine = r.x.bx;
+ }
+ else
+ *bytesPerLine = info->bpl;
+
+ pitch = ((*bytesPerLine)*8)/info->bpp;
+/* write_vga_register(0x3D4, 0x13, pitch);*/
+ clear_vga_register_bits(0x3D4, 0x50, 193);
+ clear_vga_register_bits(0x3d4, 0x50, 48);
+
+ switch ( info->bpp ) {
+ case 16 : set_vga_register_bits(0x3D4, 0x50, 16); break;
+ case 24 : set_vga_register_bits(0x3D4, 0x50, 32); break;
+ case 32 : set_vga_register_bits(0x3D4, 0x50, 48); break;
+ };
+
+ switch ( pitch ) {
+ case 640 : set_vga_register_bits(0x3D4, 0x50, 64); break;
+ case 800 : set_vga_register_bits(0x3D4, 0x50, 128); break;
+ case 1152 : set_vga_register_bits(0x3D4, 0x50, 1); break;
+ case 1280 : set_vga_register_bits(0x3D4, 0x50, 129); break;
+ case 1600 : set_vga_register_bits(0x3D4, 0x50, 192); break;
+ };
+
+ /* adjust the virtual width for widescreen modes */
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* write high bits to S3-specific registers */
+ write_vga_register(0x3D4, 0x38, 0x48);
+ alter_vga_register(0x3D4, 0x31, 0x30, a>>14);
+ alter_vga_register(0x3D4, 0x51, 0x03, a>>20);
+ write_vga_register(0x3D4, 0x38, 0);
+
+ /* write to normal VGA address registers */
+ write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
+ write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
+
+ asm volatile ("sti");
+
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i 256K flags */
+ movb $0x31, %al
+ outb %al, %dx
+ movb %ah, %al
+ orb $9, %al
+ incl %edx
+ outb %al, %dx
+ decl %edx
+
+ movb $0x35, %al /* read register 0x35 */
+ outb %al, %dx
+ incl %edx
+ inb %dx, %al
+ decl %edx
+
+ andb $0xF0, %al /* mix bits 0-3 of bank number */
+ movb %cl, %ch
+ andb $0x0F, %ch
+ orb %al, %ch
+
+ movb $0x35, %al /* write the bits 0-3 of bank number */
+ outb %al, %dx
+ incl %edx
+ movb %ch, %al
+ outb %al, %dx
+ decl %edx
+
+ movb $0x51, %al /* read register 0x51 */
+ outb %al, %dx
+ incl %edx
+ inb %dx, %al
+ decl %edx
+
+ andb $0xF3, %al /* mix bits 4-5 of bank number */
+ shrb $2, %cl
+ andb $0x0C, %cl
+ orb %al, %cl
+
+ movb $0x51, %al /* write the bits 4-5 of bank number */
+ outb %al, %dx
+ incl %edx
+ movb %cl, %al
+ outb %al, %dx
+ decl %edx
+
+ movb $0x38, %al /* disable extensions */
+ outb %al, %dx
+ incl %edx
+ xorb %al, %al
+ outb %al, %dx
+ decl %edx
+
+ popl %edx
+ popl %ecx
+ 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)
+ );
+
+ af_bank = bank;
+}
+
+void WaitTillIdle(AF_DRIVER *af) {
+ unaccelIT();
+};
+
+
+/* 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 blitvram ( int srcx, int srcy, int dstx, int dsty, int dx, int dy, int dir )
+{
+ do ; while ( inportb(0x9AE8) & 0xFF );
+ outportw(0xBAE8, 0x67);
+ outportw(0xBEE8, 0xA000);
+ outportw(0x86E8, srcx);
+ outportw(0x82E8, srcy);
+ outportw(0x8EE8, dstx);
+ outportw(0x8AE8, dsty);
+
+ outportw(0x96E8, dx-1);
+ outportw(0xBEE8, dy-1);
+ do ; while ( inportb(0x9AE8) & 0xFF ); /* 0xc013 = 14,15,7,0,2 bits set */
+ if ( dir ) outportw(0x9AE8, 0xC013); else outportw(0x9AE8, 0xC0F3);
+ /* 0xc0f3 = 14,15,8,5,1,0 bits set */
+};
+
+void copyvram ( int srcx, int srcy, int dstx, int dsty, int dx, int dy )
+{
+ int dir = 0;
+ if ( dsty < srcy || ( srcy == dsty && dstx < srcx )) dir = 0;
+ else {
+ dir = 1;
+ srcx += dx-1;
+ srcy += dy-1;
+ dstx += dx-1;
+ dsty += dy-1;
+ };
+ accelIT();
+ blitvram(srcx, srcy, dstx, dsty, dx, dy, dir);
+ if ( af_bpp > 8 && af_chipid <= S86c911A )
+ blitvram(srcx+1024, srcy, dstx+1024, dsty, dx, dy, dir);
+ unaccelIT();
+};
+
+void BitBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op)
+{
+ copyvram(left, top, dstLeft, dstTop, width, height);
+};
+
+
+
diff --git a/s3/drvhdr.c b/s3/drvhdr.c
new file mode 100644
index 0000000..a129993
--- /dev/null
+++ b/s3/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF S3 driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/s3/notes.txt b/s3/notes.txt
new file mode 100644
index 0000000..997beb1
--- /dev/null
+++ b/s3/notes.txt
@@ -0,0 +1,44 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ S3 driver implementation notes.
+
+
+
+ This is a driver for S3 chipsets. It supports 8/15/16/24/32bits color
+ modes, and has support for accelerated drawing (currently only for BitBlt
+ between vram).
+
+ This code is not portable to any platforms other than DOS+DPMI, because
+ it uses BIOS calls to set the initial video mode.
+
+
+ Accelerated functions
+ ---------------------
+
+ BitBlt - I'm sorry I didn't add more functions yet, but I haven't got a
+ time and this function was very important for me. I hope it help
+ you too. If I had a more time a I will send to Allegro new
+ functions.
+
+
+ Supported Hardware
+ ------------------
+
+ I think all earlier S3 cards and some older. I'm sure for Trio64, I
+ tested it. If somebody have a problem, please send me note and your
+ ident. number of S3 card.
+
+ Thank you, Michal Stencl
+
+
+ Original Allegro code by Shawn Hargreaves (shawn@talula.demon.co.uk)
+ Improved by Michael Bukin (M.A.Bukin@inp.nsk.su)
+ Hardware acceleration by Michal Stencl (stenclpmd@ba.telecom.sk)
+
diff --git a/start.s b/start.s
new file mode 100644
index 0000000..9ddc9a9
--- /dev/null
+++ b/start.s
@@ -0,0 +1,132 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Startup and relocation code.
+ *
+ * See readme.txt for copyright information.
+ */
+
+
+
+.data
+
+.globl _hdraddr,_reladdr
+
+_hdraddr: .long 0
+_reladdr: .long 0
+
+
+.text
+
+.globl StartDriver, PlugAndPlayInit, OemExt
+
+
+
+/* helper for relocating the driver */
+
+#define DO_RELOCATION() \
+ ; \
+ movl %ebx, _reladdr(%ebx) /* store relocations */ ; \
+ movl %edx, _hdraddr(%ebx) ; \
+ ; \
+ movl 876(%edx), %ecx /* get relocation count */ ; \
+ jecxz 1f ; \
+ ; \
+ pushl %esi /* get relocation data */ ; \
+ leal 880(%edx), %esi ; \
+ cld ; \
+ ; \
+ 0: ; \
+ lodsl ; \
+ addl %ebx, (%ebx, %eax) ; \
+ loop 0b ; \
+ ; \
+ popl %esi /* relocation is complete */
+
+
+
+/* Entry point for the standard VBE/AF interface. When used with our
+ * extension mechanism, the driver will already have been relocated by
+ * the OemExt function, so this routine must detect that and do the
+ * right thing in either case. After sorting out the relocation, it
+ * chains to a C function called SetupDriver.
+ */
+PlugAndPlayInit:
+ movl %ebx, %edx /* save base address in %edx */
+ movl 576(%ebx), %eax /* retrieve our actual address */
+ subl $PlugAndPlayInit, %eax /* subtract the linker address */
+ addl %eax, %ebx /* add to our base address */
+
+ cmpl $0, _reladdr(%ebx) /* quit if we are already relocated */
+ jne 1f
+
+ DO_RELOCATION() /* relocate ourselves */
+
+ 1:
+ pushl %edx /* do high-level initialization */
+ call _SetupDriver
+ popl %edx
+ ret
+
+
+
+/* Driver init function. This is just a wrapper for the C routine called
+ * InitDriver, with a safety check to bottle out if we are being used
+ * by a VBE/AF 1.0 program (in that case, we won't have been relocated yet
+ * so we must give up in disgust).
+ */
+StartDriver:
+ pushl %ebx /* check that we have been relocated */
+ movl 412(%ebx), %eax
+ subl $StartDriver, %eax
+ addl %eax, %ebx
+ cmpl $0, _reladdr(%ebx)
+ je 0f
+
+ call _InitDriver /* ok, this program is using VBE/AF 2.0 */
+ popl %ebx
+ ret
+
+ 0:
+ movl $-1, %eax /* argh, trying to use VBE/AF 1.0! */
+ popl %ebx
+ ret
+
+
+
+/* Extension function for the FreeBE/AF enhancements. This will be the
+ * very first thing called by a FreeBE/AF aware application, and must
+ * relocate the driver in response. On subsequent calls it will just
+ * chain to the C function called FreeBEX.
+ */
+OemExt:
+ cmpl $0x494E4954, 8(%esp) /* check for FAFEXT_INIT parameter */
+ jne 2f
+
+ pushl %ebx
+ movl 8(%esp), %ebx /* read driver address from the stack */
+ movl %ebx, %edx /* save base address in %edx */
+ movl 580(%ebx), %eax /* retrieve our actual address */
+ subl $OemExt, %eax /* subtract the linker address */
+ addl %eax, %ebx /* add to our base address */
+
+ cmpl $0, _reladdr(%ebx) /* quit if we are already relocated */
+ jne 1f
+
+ addl %edx, 580(%edx) /* relocate the OemExt pointer */
+
+ DO_RELOCATION() /* relocate the rest of the driver */
+
+ 1:
+ popl %ebx
+ movl $0x45583031, %eax /* return FAFEXT_MAGIC1 */
+ ret
+
+ 2:
+ jmp _FreeBEX /* let the driver handle this request */
diff --git a/stub/driver.c b/stub/driver.c
new file mode 100644
index 0000000..eb0a5ce
--- /dev/null
+++ b/stub/driver.c
@@ -0,0 +1,1624 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Stub driver implementation file.
+ *
+ * Note: this driver implements all the hardware accelerated
+ * functions that are used by Allegro, but does them in software.
+ * This is intended to give you an example of how they are
+ * supposed to work: in a real driver you would either implement
+ * them in hardware or leave them out altogether.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+/* Define this symbol to include emulated versions of the hardware
+ * accelerator drawing routines. Without it, the driver will only
+ * provide the minimum of functions needed for dumb framebuffer access.
+ */
+
+#define USE_ACCEL
+
+
+
+/* Define this symbol to give the install program an option of disabling
+ * some of our drawing routines.
+ */
+
+#define USE_FEATURES
+
+
+
+/* Define this symbol to disable farptr access to video memory. Without
+ * it, the FreeBE/AF hardware pointer extension will be used, avoiding
+ * reliance on the fat-DS nearptr hack.
+ */
+
+// #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 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);
+
+
+
+/* if you need some video memory for internal use by the accelerator
+ * code (for example storing pattern data), you can define this value to
+ * reserve room for yourself at the very end of the memory space, that
+ * the application will not be allowed to use.
+ */
+#define RESERVED_VRAM 0
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* list of features, so the install program can disable some of them */
+#ifdef USE_FEATURES
+
+FAF_CONFIG_DATA config_data[] =
+{
+ {
+ FAF_CFG_FEATURES,
+
+ (fafLinear | fafBanked |
+ fafDrawScan | fafDrawPattScan | fafDrawColorPattScan |
+ fafDrawRect | fafDrawPattRect | fafDrawColorPattRect |
+ fafDrawLine | fafDrawTrap | fafPutMonoImage |
+ fafBitBlt | fafBitBltSys |
+ fafSrcTransBlt | fafSrcTransBltSys)
+ },
+
+ { 0, 0 }
+};
+
+#define CFG_FEATURES config_data[0].value
+
+#endif
+
+
+
+/* at startup we use the get_vesa_info() helper function to find out
+ * what resolutions the VESA driver provides for this card, storing them
+ * in a table for future use. In a real driver you would replace this
+ * VESA code with a static list of modes and their attributes, because
+ * you would know right from the start what modes are possible on your
+ * card.
+ */
+
+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;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_linear;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+int af_fore_mix;
+int af_back_mix;
+
+
+
+/* note about VBE/AF multiple page modes: the API supports any number of
+ * video memory pages, one of which is "active" (being drawn onto), while
+ * the other is visible on your monitor. Allegro doesn't actually use
+ * this functionality, so you may safely leave it out and just reject
+ * any mode set requests with a numBuffers value greater than one, but
+ * that might upset other VBE/AF applications if they depend on this
+ * functionality. To support multiple pages, you must offset all the
+ * hardware drawing operations so their coordinate system is relative
+ * to the active page. You must also maintain an offset from the start
+ * of vram to the start of the active page in the OriginOffset of the
+ * driver structure, and adjust the OffscreenStartY and OffscreenEndY
+ * values so they will refer to the same offscreen memory region regardless
+ * of the current accelerator coordinate system. This is all handled by the
+ * SetActiveBuffer() function below, so in practice you can simply add
+ * af_active_page*af_height onto the input Y coordinate of any accelerator
+ * drawing funcs, and multiple page modes should work correctly.
+ */
+
+
+
+/* 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 != 24) && (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 linear_addr;
+ int vram_size;
+ int i;
+
+ /* find out what VESA has to say for itself */
+ if (get_vesa_info(&vram_size, &linear_addr, mode_callback) != 0)
+ return -1;
+
+ /* pointer to a list of the available mode numbers, ended by -1.
+ * Our mode numbers just count up from 1, so the mode numbers can
+ * be used as indexes into the mode_list[] table (zero is an
+ * invalid mode number, so this indexing must be offset by 1).
+ */
+ af->AvailableModes = available_modes;
+
+ /* amount of video memory in K */
+ af->TotalMemory = vram_size/1024;
+
+ /* driver attributes (see definitions in vbeaf.h) */
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ #ifdef USE_ACCEL
+ af->Attributes |= afHaveAccel2D;
+ #endif
+
+ if (linear_addr)
+ af->Attributes |= afHaveLinearBuffer;
+
+ #ifdef USE_FEATURES
+ if (!(CFG_FEATURES & fafLinear))
+ af->Attributes &= ~afHaveLinearBuffer;
+
+ if (!(CFG_FEATURES & fafBanked))
+ af->Attributes &= ~afHaveBankedBuffer;
+ #endif
+
+ /* banked memory size and location: zero if not supported */
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ /* linear framebuffer size and location: zero if not supported */
+ if (linear_addr) {
+ af->LinearSize = vram_size/1024;
+ af->LinearBasePtr = linear_addr;
+ }
+ else {
+ af->LinearSize = 0;
+ af->LinearBasePtr = 0;
+ }
+
+ /* list which ports we are going to access (only needed under Linux) */
+ af->IOPortsTable = ports_table;
+
+ /* list physical memory regions that we need to access (zero for none) */
+ for (i=0; i<4; i++) {
+ af->IOMemoryBase[i] = 0;
+ af->IOMemoryLen[i] = 0;
+ }
+
+ /* driver state variables (initialised later during the mode set) */
+ af->BufferEndX = 0;
+ af->BufferEndY = 0;
+ af->OriginOffset = 0;
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+
+ /* relocatable bank switcher (not required by Allgero) */
+ af->SetBank32 = SetBank32;
+ af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
+
+ /* extension functions */
+ af->SupplementalExt = ExtStub;
+
+ /* device driver functions */
+ 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->EnableStereoMode = NULL;
+ af->SetPaletteData = SetPaletteData;
+ af->SetGammaCorrectData = NULL;
+ af->SetBank = SetBank;
+
+ /* hardware cursor functions (impossible to emulate in software!) */
+ af->SetCursor = NULL;
+ af->SetCursorPos = NULL;
+ af->SetCursorColor = NULL;
+ af->ShowCursor = NULL;
+
+ /* wait until the accelerator hardware has finished drawing */
+ #ifdef USE_ACCEL
+ af->WaitTillIdle = WaitTillIdle;
+ #endif
+
+ /* on some cards the CPU cannot access the framebuffer while it is in
+ * hardware drawing mode. If this is the case, you should fill in these
+ * functions with routines to switch in and out of the accelerator mode.
+ * The application will call EnableDirectAccess() whenever it is about
+ * to write to the framebuffer directly, and DisableDirectAccess()
+ * before it calls any hardware drawing routines. If this arbitration is
+ * not required, leave these routines as NULL.
+ */
+ af->EnableDirectAccess = NULL;
+ af->DisableDirectAccess = NULL;
+
+ /* sets the hardware drawing mode (solid, XOR, etc) */
+ #ifdef USE_ACCEL
+ af->SetMix = SetMix;
+ #endif
+
+ /* pattern download functions. May be NULL if patterns not supported */
+ #ifdef USE_ACCEL
+ af->Set8x8MonoPattern = Set8x8MonoPattern;
+ af->Set8x8ColorPattern = Set8x8ColorPattern;
+ af->Use8x8ColorPattern = Use8x8ColorPattern;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->SetLineStipple = NULL;
+ af->SetLineStippleCount = NULL;
+
+ /* not supported. There really isn't much point in this function because
+ * a lot of hardware can't do clipping at all, and even when it can there
+ * are usually problems with very large or negative coordinates. This
+ * means that a software clip is still required, so you may as well
+ * ignore this routine.
+ */
+ af->SetClipRect = NULL;
+
+ /* acclerated drivers must support DrawScan(), but patterns may be NULL */
+ #ifdef USE_ACCEL
+ af->DrawScan = DrawScan;
+ af->DrawPattScan = DrawPattScan;
+ af->DrawColorPattScan = DrawColorPattScan;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->DrawScanList = NULL;
+ af->DrawPattScanList = NULL;
+ af->DrawColorPattScanList = NULL;
+
+ /* rectangle filling: may be NULL */
+ #ifdef USE_ACCEL
+ af->DrawRect = DrawRect;
+ af->DrawPattRect = DrawPattRect;
+ af->DrawColorPattRect = DrawColorPattRect;
+ #endif
+
+ /* line drawing: may be NULL */
+ #ifdef USE_ACCEL
+ af->DrawLine = DrawLine;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->DrawStippleLine = NULL;
+
+ /* trapezoid filling: may be NULL */
+ #ifdef USE_ACCEL
+ af->DrawTrap = DrawTrap;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->DrawTri = NULL;
+ af->DrawQuad = NULL;
+
+ /* monochrome character expansion: may be NULL */
+ #ifdef USE_ACCEL
+ af->PutMonoImage = PutMonoImage;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->PutMonoImageLin = NULL;
+ af->PutMonoImageBM = NULL;
+
+ /* opaque blitting: may be NULL */
+ #ifdef USE_ACCEL
+ af->BitBlt = BitBlt;
+ af->BitBltSys = BitBltSys;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->BitBltLin = NULL;
+ af->BitBltBM = NULL;
+
+ /* masked blitting: may be NULL */
+ #ifdef USE_ACCEL
+ af->SrcTransBlt = SrcTransBlt;
+ af->SrcTransBltSys = SrcTransBltSys;
+ #endif
+
+ /* not supported: not used by Allegro */
+ af->SrcTransBltLin = NULL;
+ af->SrcTransBltBM = NULL;
+ af->DstTransBlt = NULL;
+ af->DstTransBltSys = NULL;
+ af->DstTransBltLin = NULL;
+ af->DstTransBltBM = NULL;
+ af->StretchBlt = NULL;
+ af->StretchBltSys = NULL;
+ af->StretchBltLin = NULL;
+ af->StretchBltBM = NULL;
+ af->SrcTransStretchBlt = NULL;
+ af->SrcTransStretchBltSys = NULL;
+ af->SrcTransStretchBltLin = NULL;
+ af->SrcTransStretchBltBM = NULL;
+ af->DstTransStretchBlt = NULL;
+ af->DstTransStretchBltSys = NULL;
+ af->DstTransStretchBltLin = NULL;
+ af->DstTransStretchBltBM = NULL;
+ af->SetVideoInput = NULL;
+ af->SetVideoOutput = NULL;
+ af->StartVideoFrame = NULL;
+ af->EndVideoFrame = NULL;
+
+ /* allow the install program to disable some features */
+ #ifdef USE_FEATURES
+ fixup_feature_list(af, CFG_FEATURES);
+ #endif
+
+ 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
+
+ #ifdef USE_FEATURES
+
+ case FAFEXT_CONFIG:
+ /* allow the install program to configure our driver */
+ return config_data;
+
+ #endif
+
+ default:
+ return NULL;
+ }
+}
+
+
+
+/* ExtStub:
+ * Supplemental 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);
+
+ #ifdef USE_ACCEL
+ modeInfo->Attributes |= afHaveAccel2D;
+ #endif
+
+ if (info->linear)
+ modeInfo->Attributes |= afHaveLinearBuffer;
+
+ #ifdef USE_FEATURES
+ if (!(CFG_FEATURES & fafLinear))
+ modeInfo->Attributes &= ~afHaveLinearBuffer;
+
+ if (!(CFG_FEATURES & fafBanked))
+ modeInfo->Attributes &= ~afHaveBankedBuffer;
+ #endif
+
+ 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->bytes_per_scanline * info->h);
+
+ /* maximum virtual scanline length in both bytes and pixels. How wide
+ * this can go will very much depend on the card: 1024 is pretty safe
+ * on anything, but you will want to allow larger limits if the card
+ * is capable of them.
+ */
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+
+ /* 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)
+{
+ int linear = ((mode & 0x4000) != 0);
+ int noclear = ((mode & 0x8000) != 0);
+ long available_vram;
+ long used_vram;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo */
+ if (mode & 0x400)
+ return -1;
+
+ /* reject linear/banked modes if the install program has disabled them */
+ #ifdef USE_FEATURES
+ if (linear) {
+ if (!(CFG_FEATURES & fafLinear))
+ return -1;
+ }
+ else {
+ if (!(CFG_FEATURES & fafBanked))
+ return -1;
+ }
+ #endif
+
+ /* 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;
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX*BYTES_PER_PIXEL(info->bpp) > info->bytes_per_scanline) {
+ r.x.ax = 0x4F06;
+ r.x.bx = 0;
+ r.x.cx = virtualX;
+ rm_int(0x10, &r);
+ if (r.h.ah)
+ return -1;
+ *bytesPerLine = r.x.bx;
+ }
+ else
+ *bytesPerLine = info->bytes_per_scanline;
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_linear = linear;
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ /* return framebuffer dimensions to the application */
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 - RESERVED_VRAM;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ af_fore_mix = AF_REPLACE_MIX;
+ af_back_mix = AF_FORE_MIX;
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ RM_REGS r;
+
+ if (waitVRT >= 0) {
+ r.x.ax = 0x4F07;
+ r.x.bx = (waitVRT) ? 0x80 : 0;
+ r.x.cx = x;
+ r.x.dx = y + af_visible_page*af_height;
+
+ rm_int(0x10, &r);
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i>16;
+ if (bank != af_bank) {
+ af->SetBank(af, bank);
+ af_bank = bank;
+ }
+ p = &hwptr.BankedMem;
+ offset &= 0xFFFF;
+ }
+
+ if (mix != AF_REPLACE_MIX) {
+ /* read destination pixel for mixing */
+ switch (af_bpp) {
+
+ case 8:
+ c2 = hwptr_peekb(*p, offset);
+ break;
+
+ case 15:
+ case 16:
+ c2 = hwptr_peekw(*p, offset);
+ break;
+
+ case 24:
+ c2 = hwptr_peekl(*p, offset) & 0xFFFFFF;
+ break;
+
+ case 32:
+ c2 = hwptr_peekl(*p, offset);
+ break;
+ }
+
+ /* apply logical mix modes */
+ switch (mix) {
+
+ case AF_AND_MIX:
+ c &= c2;
+ break;
+
+ case AF_OR_MIX:
+ c |= c2;
+ break;
+
+ case AF_XOR_MIX:
+ c ^= c2;
+ break;
+ }
+ }
+
+ /* write the pixel */
+ switch (af_bpp) {
+
+ case 8:
+ hwptr_pokeb(*p, offset, c);
+ break;
+
+ case 15:
+ case 16:
+ hwptr_pokew(*p, offset, c);
+ break;
+
+ case 24:
+ hwptr_pokew(*p, offset, c&0xFFFF);
+ hwptr_pokeb(*p, offset+2, c>>16);
+ break;
+
+ case 32:
+ hwptr_pokel(*p, offset, c);
+ break;
+ }
+}
+
+
+
+/* af_getpixel:
+ * Reads a pixel from the screen. This function is _not_ intended to
+ * be useful: it is grossly inefficient! It is just a helper for the
+ * example drawing routines below: these should of course be replaced
+ * by hardware specific code.
+ */
+int af_getpixel(AF_DRIVER *af, int x, int y)
+{
+ FAF_HWPTR *p;
+ long offset;
+ int bank;
+
+ y += af_active_page*af_height;
+ offset = y*af_width + x*BYTES_PER_PIXEL(af_bpp);
+
+ /* get pointer to vram */
+ if (af_linear) {
+ p = &hwptr.LinearMem;
+ }
+ else {
+ bank = offset>>16;
+ if (bank != af_bank) {
+ af->SetBank(af, bank);
+ af_bank = bank;
+ }
+ p = &hwptr.BankedMem;
+ offset &= 0xFFFF;
+ }
+
+ /* read the pixel */
+ switch (af_bpp) {
+
+ case 8:
+ return hwptr_peekb(*p, offset);
+
+ case 15:
+ case 16:
+ return hwptr_peekw(*p, offset);
+
+ case 24:
+ return hwptr_peekl(*p, offset) & 0xFFFFFF;
+
+ case 32:
+ return hwptr_peekl(*p, offset);
+ }
+
+ return 0;
+}
+
+
+
+/* mem_getpixel:
+ * Reads a pixel from an image stored in system memory. This function is
+ * _not_ intended to be useful: it is grossly inefficient! It is just a
+ * helper for the example drawing routines below.
+ */
+int mem_getpixel(void *addr, int pitch, int x, int y)
+{
+ addr += y*pitch + x*BYTES_PER_PIXEL(af_bpp);
+
+ switch (af_bpp) {
+
+ case 8:
+ return *((unsigned char *)addr);
+
+ case 15:
+ case 16:
+ return *((unsigned short *)addr);
+
+ case 24:
+ return *((unsigned long *)addr) & 0xFFFFFF;
+
+ case 32:
+ return *((unsigned long *)addr);
+ }
+
+ return 0;
+}
+
+
+
+/* stored mono pattern data */
+unsigned char mono_pattern[8];
+
+
+
+/* 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)
+{
+ int i;
+
+ for (i=0; i<8; i++)
+ mono_pattern[i] = pattern[i];
+}
+
+
+
+/* stored color pattern data */
+unsigned long color_pattern[8][64];
+unsigned long *current_color_pattern = color_pattern[0];
+
+
+
+/* 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).
+ *
+ * VBE/AF supports 8 different color patterns, which may be downloaded
+ * individually and then selected for use with the Use8x8ColorPattern()
+ * function. If the card is not able to cache these patterns in hardware,
+ * the driver is responsible for storing them internally and downloading
+ * the appropriate data when Use8x8ColorPattern() is called.
+ *
+ * Allegro only actually ever uses the first of these patterns, so
+ * you only need to bother about this if you want your code to work
+ * with other programs as well.
+ */
+void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
+{
+ int i;
+
+ for (i=0; i<64; i++)
+ color_pattern[index][i] = pattern[i];
+}
+
+
+
+/* Use8x8ColorPattern:
+ * Selects one of the patterns previously downloaded by Set8x8ColorPattern().
+ */
+void Use8x8ColorPattern(AF_DRIVER *af, int index)
+{
+ current_color_pattern = 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)
+{
+ int orig_bank = af_bank;
+
+ if (x2 < x1) {
+ int tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ while (x1 < x2) {
+ af_putpixel(af, x1, y, color, af_fore_mix);
+ x1++;
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* 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)
+{
+ int orig_bank = af_bank;
+ int patx, paty;
+
+ if (x2 < x1) {
+ int tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ while (x1 < x2) {
+ patx = x1&7;
+ paty = y&7;
+
+ if (mono_pattern[paty] & (0x80>>patx))
+ af_putpixel(af, x1, y, foreColor, af_fore_mix);
+ else
+ af_putpixel(af, x1, y, backColor, af_back_mix);
+
+ x1++;
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* DrawColorPattScan:
+ * Fills a scanline using the current color pattern and mix mode.
+ */
+void DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2)
+{
+ int orig_bank = af_bank;
+ int patx, paty;
+
+ if (x2 < x1) {
+ int tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+
+ while (x1 < x2) {
+ patx = x1&7;
+ paty = y&7;
+
+ af_putpixel(af, x1, y, current_color_pattern[paty*8+patx], af_fore_mix);
+
+ x1++;
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* 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)
+{
+ int orig_bank = af_bank;
+ int x, y;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* 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)
+{
+ int orig_bank = af_bank;
+ int patx, paty;
+ int x, y;
+
+ for (y=0; y>patx))
+ af_putpixel(af, left+x, top+y, foreColor, af_fore_mix);
+ else
+ af_putpixel(af, left+x, top+y, backColor, af_back_mix);
+ }
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* 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 orig_bank = af_bank;
+ int patx, paty;
+ int x, y;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* DrawLine:
+ * Draws a line between the two specified points (inclusive of both),
+ * which are specified in 16.16 fixed point format, using the current
+ * foreground mix mode.
+ */
+void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2)
+{
+ int orig_bank = af_bank;
+ int start, end, dir, p;
+ fixed delta;
+
+ if (ABS(x1-x2) > ABS(y1-y2)) {
+ /* x-driven drawer */
+ start = (x1 >> 16) + ((x1 & 0x8000) >> 15);
+ end = (x2 >> 16) + ((x2 & 0x8000) >> 15);
+ dir = (start < end) ? 1 : -1;
+
+ if (start != end)
+ delta = (y2-y1) / ABS(start-end);
+ else
+ delta = 0;
+
+ while (start != end+dir) {
+ p = (y1 >> 16) + ((y1 & 0x8000) >> 15);
+ af_putpixel(af, start, p, color, af_fore_mix);
+ start += dir;
+ y1 += delta;
+ }
+ }
+ else {
+ /* y-driven drawer */
+ start = (y1 >> 16) + ((y1 & 0x8000) >> 15);
+ end = (y2 >> 16) + ((y2 & 0x8000) >> 15);
+ dir = (start < end) ? 1 : -1;
+
+ if (start != end)
+ delta = (x2-x1) / ABS(start-end);
+ else
+ delta = 0;
+
+ while (start != end+dir) {
+ p = (x1 >> 16) + ((x1 & 0x8000) >> 15);
+ af_putpixel(af, p, start, color, af_fore_mix);
+ start += dir;
+ x1 += delta;
+ }
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* DrawTrap:
+ * Fills a trapezoid, using the current foreground mix mode. This is a
+ * workhorse routine used for polygon filling. The x coordinates and slope
+ * values in the AF_TRAP structure specify position and deltas for both
+ * sides of the shape in 16.16 fixed point format. The two edges are
+ * allowed to cross, and the fill should be inclusive of the left edge but
+ * exclusive of the right. At the end of the routine, the x coordinates
+ * in the AF_TRAP structure should be updated to reflect their modified
+ * positions after the edge has been traced.
+ */
+void DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap)
+{
+ int ix1, ix2;
+
+ while (trap->count--) {
+ ix1 = (trap->x1 >> 16) + ((trap->x1 & 0x8000) >> 15);
+ ix2 = (trap->x2 >> 16) + ((trap->x2 & 0x8000) >> 15);
+
+ if (ix2 < ix1) {
+ int tmp = ix1;
+ ix1 = ix2;
+ ix2 = tmp;
+ }
+
+ if (ix1 < ix2)
+ DrawScan(af, color, trap->y, ix1, ix2);
+
+ trap->x1 += trap->slope1;
+ trap->x2 += trap->slope2;
+ trap->y++;
+ }
+}
+
+
+
+/* PutMonoImage:
+ * Expands a monochrome image from system memory onto the screen. Set 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 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)
+{
+ int orig_bank = af_bank;
+ unsigned char c;
+ int x, y;
+
+ for (y=0; y>((srcX+x)&7)))
+ af_putpixel(af, dstX+x, dstY+y, foreColor, af_fore_mix);
+ else
+ af_putpixel(af, dstX+x, dstY+y, backColor, af_back_mix);
+ }
+ }
+
+ if (af_bank != orig_bank)
+ af->SetBank(af, orig_bank);
+}
+
+
+
+/* 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 orig_bank = af_bank;
+ int x, y, c;
+
+ if ((left+width > dstLeft) && (top+height > dstTop) &&
+ (dstLeft+width > left) && (dstTop+height > top) &&
+ ((dstTop > top) || ((dstTop == top) && (dstLeft > left)))) {
+ /* have to do the copy backward */
+ for (y=height-1; y>=0; y--) {
+ for (x=width-1; x>=0; x--) {
+ c = af_getpixel(af, left+x, top+y);
+ af_putpixel(af, dstLeft+x, dstTop+y, c, op);
+ }
+ }
+ }
+ else {
+ /* copy in the normal forwards direction */
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* BitBltSys:
+ * Copies an image from system memory onto 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 orig_bank = af_bank;
+ int x, y, c;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* 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 orig_bank = af_bank;
+ int x, y, c;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
+
+
+/* SrcTransBltSys:
+ * Copies an image from system memory onto the screen, skipping any source
+ * pixels which 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 orig_bank = af_bank;
+ int x, y, c;
+
+ for (y=0; ySetBank(af, orig_bank);
+}
+
diff --git a/stub/drvhdr.c b/stub/drvhdr.c
new file mode 100644
index 0000000..af496d9
--- /dev/null
+++ b/stub/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0, /* DriverRev */
+ "FreeBE/AF stub driver implementation " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ -1, /* PCIVendorID */
+ -1, /* PCIDeviceID */
+ -1, /* PCISubSysVendorID */
+ -1, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/stub/notes.txt b/stub/notes.txt
new file mode 100644
index 0000000..d12f039
--- /dev/null
+++ b/stub/notes.txt
@@ -0,0 +1,86 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ Stub driver implementation notes.
+
+
+
+ This is an example driver implementation, intended as a starting point
+ for anyone who wants to make a real driver for a specific card. It
+ provides all the essential VBE/AF functions, but it runs on top of your
+ existing VESA driver, using VESA calls to set the video mode and then
+ simple software drawing functions to emulate the hardware accelerated
+ operations. As such it is not useful in any practical way, but it does
+ work: just copy the vbeaf.drv file to c:\ and you should be able to use
+ it from any Allegro programs, or the SciTech VBETEST utility (run
+ "vbetest -f" to use VBE/AF rather than regular VESA).
+
+ This driver is not portable, because it uses DPMI calls to communicate
+ with VESA. This is no problem as long as it is being used with Allegro,
+ but the binary will not work on any other platforms until you have
+ removed all the VESA calls and are using direct hardware access for
+ everything.
+
+ This driver provides "accelerated" (emulated in software, and painfully
+ slow, but they look like hardware functions to the calling program),
+ versions of the VBE/AF routines:
+
+ WaitTillIdle()
+ SetMix()
+ Set8x8MonoPattern()
+ Set8x8ColorPattern()
+ Use8x8ColorPattern()
+ DrawScan()
+ DrawPattScan()
+ DrawColorPattScan()
+ DrawRect()
+ DrawPattRect()
+ DrawColorPattRect()
+ DrawLine()
+ DrawTrap()
+ PutMonoImage()
+ BitBlt()
+ BitBltSys()
+ SrcTransBlt()
+ SrcTransBltSys()
+
+ If you don't want to support all these in your driver, they should be
+ replaced with NULL pointers so the caller will know to use their normal
+ drawing code instead. VBE/AF provides many more routines than these, but
+ Allegro only uses the ones from that list, so it would be rather futile
+ to implement any others.
+
+ This driver supports the FreeBE/AF extension mechanism for enabling true
+ protected mode access to video memory. Uncomment the definition of
+ NO_HWPTR at the top of driver.c if you want to return to the standard
+ nearptr memory access.
+
+ If you comment out the definition of USE_ACCEL at the top of driver.c,
+ the emulated acceleration routines will be removed, leaving only a dumb
+ framebuffer driver. This may be useful to see what is the bare minimum of
+ functions that you need to include in a VBE/AF driver.
+
+ This driver implements the FreeBE/AF FAF_CFG_FEATURES extension
+ mechanism, which allows the installation program to selectively disable
+ some of the hardware accelerated drawing routines. Comment out the
+ definition of USE_FEATURES at the top of driver.c if you want to remove
+ this capability.
+
+ There is no support for hardware cursors, 8 bit DAC modes, or the refresh
+ rate control functions.
+
+ The VESA implementation assumes a single 64k memory bank, so it will not
+ function correctly on cards with dual banks or other granularities. This
+ won't be a problem for the real drivers, though, because you will know
+ the granularity in advance. VBE/AF only allows 4k or 64k, so other sizes
+ must be scaled up to 64k units.
+
+
+ By Shawn Hargreaves
+ shawn@talula.demon.co.uk
diff --git a/tgui/driver.c b/tgui/driver.c
new file mode 100644
index 0000000..5159a54
--- /dev/null
+++ b/tgui/driver.c
@@ -0,0 +1,2649 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/*
+ E-mail: salvador@inti.gov.ar, set-soft@usa.net, set@computer.org
+*/
+/* Note: Currently it means: you can use it for any purpose. But if the
+ project changes it could change so check the FreeBE/AF readmes.
+ Additionally: if anybody uses part of this code please let me know to add
+it to my curriculum. */
+/*****************************************************************************
+
+Implemented:
+
+SetMix, Set8x8MonoPattern, Set8x8ColorPattern, Use8x8ColorPattern
+DrawLine, SetLineStipple, SetLineStippleCount, DrawStippleLine
+DrawRect, DrawScan, DrawPattRect, DrawPattScan, DrawColorPattRect
+DrawColorPattScan
+BitBlt, SrcTransBlt
+SetCursor, SetCursorPos, SetCursorColor (*), ShowCursor
+SetBank, SetBank32, SetPaletteData, GetDisplayStartStatus (*2)
+SetDisplayStart, SetActiveBuffer, SetVisibleBuffer
+GetVideoModeInfo, SetVideoMode, WaitTillIdle, SetupDriver, InitDriver
+RestoreTextMode, EnableDirectAccess, DisableDirectAccess,
+GetClosestPixelClock
+BitBltSys, SrcTransBltSys, PutMonoImage
+DrawScanList, DrawPattScanList, DrawColorPattScanList
+DrawTrap (*3)
+
+From Inertia: (Old functions conditionally included because seems they won't
+be used)
+
+GetConfigInfo,GetCurrentMode,SetVSyncWidth,GetVSyncWidth,GetBank,
+GetVisibleBuffer,GetDisplayStart,SetDisplayStartAddr,IsVSync,WaitVSync,
+GetActiveBuffer,IsIdle
+
+(*) See implementation notes
+(*2) Dummy because looks like TGUI doesn't set the interrupt flag.
+(*3) Implemented using scans because isn't supported by the hard.
+
+The following are not supported by 9440:
+
+Implementation notes:
+
+* TGUI9440 doesn't support acelerations in 24 bpp, I must check if the
+cursor works.
+* TGUI9440 doesn't support Background Mix, as I think the only routine that
+needs it is DrawPattRect (and your equivalent Scan) I did a trick:
+a) When fore and back mix are the same (most of the time) I ignore back mix.
+b) When back mix is "No Operation" (Destination) I use a transparent mode.
+c) When both are important I use 2 steps, first makes a transparent blit
+with the fore mix, and the second uses an inverted patterned and is done
+using the back mix as fore mix.
+I hope that is better than soft fills.
+* The cursor uses color index 0 for the main color and color index 0xFF for
+the xor area. I think it could be very annoying in 8bpp modes perhaps I must
+disable the cursor on these modes.
+* Supported video modes:
+ 8 bpp 15 bpp 16 bpp 24 bpp
+ 320x200 * * * *
+ 320x240 * * * *
+ 400x300 * * * *
+ 512x384 * * * *
+ 576x432 * * * *
+ 640x400 * * * *
+ 640x480 * * * *
+ 720x540 * * * *
+ 800x600 * * * *
+ 900x675 * * * *
+1024x768 * * * (1)
+
+(1) Needs more than 2Mb so is impossible with 9440
+
+*****************************************************************************/
+
+/* Define it if you don't want to call WaitTillIdle, I doubt somebody could
+ really want it */
+//#define WAITTILLIDLE_NOT_NEEDED
+
+#include
+#include "mytypes.h"
+#include "vga.h"
+#include "vbeaf.h"
+#include "tgui.h"
+#include "setmode.h"
+#define VBE_AF_INCLUDED
+
+#define NULL 0
+
+#define TEST_MODE_INTERNAL
+//#define X11Cursor
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void SetBank32();
+void SetBank32End();
+#ifdef __cplusplus
+}
+#endif
+
+void WaitTillIdle(AF_DRIVER *af);
+
+uchar ROPEquiv[32]={
+ROP_P, /* 0x00: AF_REPLACE_MIX => Source */
+ROP_PaD, /* 0x01: AF_AND_MIX => And */
+ROP_PoD, /* 0x02: AF_OR_MIX => Or */
+ROP_PxD, /* 0x03: AF_XOR_MIX => XOr */
+ROP_D, /* 0x04: AF_NOP_MIX => Destination */
+ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,
+/* Pattern operation as defined by Windows
+ Note: Pat is pen (color) for line drawing */
+ROP_0, /* 0x10: AF_R2_BLACK => 0 */
+ROP_n_PoD, /* 0x11: AF_R2_NOTMERGESRC => NOr Pat */
+ROP_nPaD, /* 0x12: AF_R2_MASKNOTSRC => !Pat & Dest */
+ROP_nP, /* 0x13: AF_R2_NOTCOPYSRC => !Pat */
+ROP_PanD, /* 0x14: AF_R2_MASKSRCNOT => Pat & !Dest */
+ROP_nD, /* 0x15: AF_R2_NOT => !Dest */
+ROP_PxD, /* 0x16: AF_R2_XORSRC => XOr Pat*/
+ROP_n_PaD, /* 0x17: AF_R2_NOTMASKSRC => NAnd Pat */
+ROP_PaD, /* 0x18: AF_R2_MASKSRC => And Pat */
+ROP_n_PxD, /* 0x19: AF_R2_NOTXORSRC => XNOr Pat */
+ROP_D, /* 0x1A: AF_R2_NOP => Dest */
+ROP_nPoD, /* 0x1B: AF_R2_MERGENOTSRC => !Pat | Dest */
+ROP_P, /* 0x1C: AF_R2_COPYSRC => Pat */
+ROP_PonD, /* 0x1D: AF_R2_MERGESRCNOT => Pat | !Dest */
+ROP_PoD, /* 0x1E: AF_R2_MERGESRC => Or Pat */
+ROP_1 /* 0x1F: AF_R2_WHITE => 1 */
+};
+
+uchar ROPImageEquiv[32]={
+ROP_S, /* 0x00: AF_REPLACE_MIX => Source */
+ROP_SaD, /* 0x01: AF_AND_MIX => And */
+ROP_SoD, /* 0x02: AF_OR_MIX => Or */
+ROP_SxD, /* 0x03: AF_XOR_MIX => XOr */
+ROP_D, /* 0x04: AF_NOP_MIX => Destination */
+ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,ROP_D,
+ROP_0, /* 0x10: AF_R2_BLACK => 0 */
+ROP_n_SoD, /* 0x11: AF_R2_NOTMERGESRC => NOr Image */
+ROP_nSaD, /* 0x12: AF_R2_MASKNOTSRC => !Image & Dest */
+ROP_nS, /* 0x13: AF_R2_NOTCOPYSRC => !Image */
+ROP_SanD, /* 0x14: AF_R2_MASKSRCNOT => Image & !Dest */
+ROP_nS, /* 0x15: AF_R2_NOT => !Dest */
+ROP_SxD, /* 0x16: AF_R2_XORSRC => XOr Image*/
+ROP_n_SaD, /* 0x17: AF_R2_NOTMASKSRC => NAnd Image */
+ROP_SaD, /* 0x18: AF_R2_MASKSRC => And Image */
+ROP_n_SxD, /* 0x19: AF_R2_NOTXORSRC => XNOr Image */
+ROP_D, /* 0x1A: AF_R2_NOP => Dest */
+ROP_nSoD, /* 0x1B: AF_R2_MERGENOTSRC => !Image | Dest */
+ROP_S, /* 0x1C: AF_R2_COPYSRC => Image */
+ROP_SonD, /* 0x1D: AF_R2_MERGESRCNOT => Image | !Dest */
+ROP_SoD, /* 0x1E: AF_R2_MERGESRC => Or Image */
+ROP_1 /* 0x1F: AF_R2_WHITE => 1 */
+};
+
+ushort PortsTable[]={
+/* VGA registers */
+ 0x3C0,0x3C1,0x3C2,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CC,0x3CE,
+ 0x3CF,0x3D4,0x3D5,0x3DA,
+ /* TGUI registers */
+ 0x3D8,0x3D9,0x3DB,0x43C6,0x43C7,0x43C8,0x43C9,0x83C6,0x83C8,
+ #ifdef IOMAPPED
+ 0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127,
+ 0x2128,0x2129,0x212A,0x212B,0x212C,0x212D,0x212E,0x212F,
+ 0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137,
+ 0x2138,0x2139,0x213A,0x213B,0x213C,0x213D,0x213E,0x213F,
+ 0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147,
+ #endif
+ 0xFFFF
+};
+
+static char tBytesPerPixel[]={1,2,2,3};
+static char tBitsPerPixel[]={8,15,16,24};
+
+/* Variables to handle the Fore/Back Mixing */
+uchar UsesBackMix=0;
+uchar DontMakeBackMix=0;
+uchar BackMix=ROP_P;
+uchar LineForegroundMix=ROP_P;
+uchar LineForegroundMixToS=ROP_S;
+uchar CurrentForegroundMix=ROP_P;
+uchar HaveDoubleScan=0;
+uchar IsAceleratorOn=0;
+
+unsigned MMIOBASE;
+unsigned long linearAddress;
+unsigned long bankedAddress;
+unsigned AvailableRAM;
+unsigned CursorPat;
+unsigned pCursorPat;
+unsigned ColorPatterns[8];
+unsigned pColorPatterns[8];
+unsigned MonoPattern,InvMonoPattern;
+unsigned pMonoPattern,pInvMonoPattern;
+unsigned SelectedColorPattern;
+unsigned *TextModeMemory;
+int afCurrentMode=0;
+int afCurrentBank=0;
+
+unsigned af_y=0;
+unsigned af_color_pattern=0;
+unsigned af_bpp;
+unsigned af_bytespp;
+unsigned af_visible_page=0;
+unsigned af_active_page=0;
+unsigned af_height=480;
+unsigned af_width_bytes=1024;
+unsigned af_scroll_x;
+unsigned af_scroll_y;
+
+/* ToDo: perhaps optimize it */
+static inline
+void Memcpy(uchar *d, uchar *s, int size)
+{
+ while (size--)
+ *(d++)=*(s++);
+}
+
+/*#define BASE_PSEUDO_DMA linearAddress*/
+/* Ivan's motherboard have a VERY slow access to the LFB so blits are slower
+ if we blit to the LFB */
+#define BASE_PSEUDO_DMA bankedAddress
+
+/**[txh]********************************************************************
+
+ Description:
+ This function tests the video memory. I use 256Kb steps because I think
+less than it is impossible. In fact I think all the 9440 boards have 1Mb
+or 2Mb of memory. Some time ago I tried to install 1.5Mb in one board and
+the BIOS reported just 1Mb. I also tried removing 0.5Mb and the BIOS
+detected it OK. I think Trident's BIOS detects 256, 512, 1024 and 2048.
+ The first time I tested this function writing outside the memory didn't
+write, but when I tested it in my machine it made a write at the 0 position.
+The stranger thing is that it doesn't happend with unoptimized code.
+ Oh! if you wander about why such a complex test, beleive me if you don't
+check all you could detect any crazy value.
+
+***************************************************************************/
+#define M256K (1<<18)
+#define M512K (1<<19)
+#define M2M (1<<21)
+
+#if 1
+int TestMemory()
+{
+ /* Brut force: Try read/write to the linear space ;-) */
+ int size=1<<18;
+ volatile uchar *p=((uchar *)linearAddress);
+ uchar temp;
+ uchar temp0,temp1,temp2;
+ int seq04,crt1e;
+
+ /* Put the chip in a mode where we can address the whole memory */
+ seq04=ReadSEQ(4);
+ crt1e=ReadCRT(0x1E);
+ if ((seq04 & 8)==0)
+ WriteSEQ(4,seq04 | 8); /* Chain 4 */
+ if ((crt1e & 0x80)==0)
+ WriteCRT(0x1E,crt1e | 0x80); /* Enable b16 start address */
+
+ temp0=*p; temp1=p[M256K]; temp2=p[M512K];
+ *p=0xF0; p[M256K]=0xF0; p[M512K]=0xF0;
+ if (*p!=0xF0)
+ size=0;
+ else
+ {
+ do
+ {
+ temp=p[size];
+ p[size]=0xAA;
+ p[4]=0;
+ if (p[size]!=0xAA || *p!=0xF0)
+ break;
+ if (size>M256K)
+ {
+ if (p[M256K]!=0xF0)
+ break;
+ if (size>M512K && p[M512K]!=0xF0)
+ break;
+ }
+ p[size]=0x55;
+ p[4]=0;
+ if (p[size]!=0x55 || *p!=0xF0)
+ break;
+ if (size>M256K)
+ {
+ if (p[M256K]!=0xF0)
+ break;
+ if (size>M512K && p[M512K]!=0xF0)
+ break;
+ }
+ p[size]=temp;
+ size+=M256K;
+ }
+ while (size>6;
+ AvailableRAM-=128;
+ pInvMonoPattern=linearAddress+AvailableRAM;
+ InvMonoPattern=AvailableRAM>>6;
+ /* Hardware Cursor */
+ /* 32x32 (size) * 2 (planes) / 8 (packed) = 256 but 1K aligned */
+ AvailableRAM-=256+512;
+ pCursorPat=linearAddress+AvailableRAM;
+ CursorPat=AvailableRAM>>10;
+ /* 8 patterns of 8x8x2 bytes */
+ for (i=0; i<8; i++)
+ {
+ AvailableRAM-=128;
+ pColorPatterns[i]=linearAddress+AvailableRAM;
+ ColorPatterns[i]=AvailableRAM>>6;
+ }
+ SelectedColorPattern=ColorPatterns[0];
+}
+#endif
+
+/**[txh]********************************************************************
+
+ Description:
+ 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. @x{DrawPattScan}.
+@x{DrawPattRect}.
+
+***************************************************************************/
+
+void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern)
+{
+ #ifndef WAITTILLIDLE_NOT_NEEDED
+ WaitGE();
+ #endif
+ *((unsigned long *)pMonoPattern) = *((unsigned long *)pattern);
+ *((unsigned long *)pInvMonoPattern) = ~(*((unsigned long *)pattern));
+ *((unsigned long *)(pMonoPattern+4)) = *((unsigned long *)&pattern[4]);
+ *((unsigned long *)(pInvMonoPattern+4)) = ~(*((unsigned long *)&pattern[4]));
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ 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).
+@x{DrawColorPattScan}. @x{DrawColorPattRect}.
+
+// ToDo: Make 2 versions
+
+***************************************************************************/
+
+void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern)
+{
+ int i;
+ index&=0x7;
+ if (af_bpp==8)
+ {
+ #ifndef WAITTILLIDLE_NOT_NEEDED
+ WaitGE();
+ #endif
+ for (i=0; i<64; i++)
+ *(((uchar *)pColorPatterns[index])+i)=pattern[i];
+ }
+ else
+ {
+ #ifndef WAITTILLIDLE_NOT_NEEDED
+ WaitGE();
+ #endif
+ for (i=0; i<64; i++)
+ *(((ushort *)pColorPatterns[index])+i)=pattern[i];
+ }
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Selects one of the patterns previously downloaded by Set8x8ColorPattern().
+@x{Set8x8ColorPattern}.
+
+***************************************************************************/
+
+void Use8x8ColorPattern(AF_DRIVER *af, int index)
+{
+ SelectedColorPattern=ColorPatterns[index & 0x7];
+}
+
+
+/*****************************************************************************
+
+ The TGUI9440 chip supports only Besenham lines, I think they are VERY easy
+to implement in chips and that's the reason because old chips use it.
+ These lines works with parameters for one octant, the one defined by:
+
+ delta X > delta Y > 0
+
+ To create any line the chip provides 3 bits that selects the octant.
+
+*****************************************************************************/
+
+void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2)
+{
+ int dX,dY,dir=SolidDrawing | PatFromDisplay | SourceDataDisplay;
+
+ /* round coordinates from fixed point to integer */
+ x1=(x1+0x8000)>>16;
+ y1=((y1+0x8000)>>16)+af_y;
+ x2=(x2+0x8000)>>16;
+ y2=((y2+0x8000)>>16)+af_y;
+
+ /* Check if dY is positive */
+ if (y1>y2)
+ { /* No then reverse Y direction */
+ dir|=YDecreasing;
+ dY=y1-y2;
+ }
+ else
+ dY=y2-y1;
+
+ /* Check if dX is positive */
+ if (x1>x2)
+ { /* No then reverse Y direction */
+ dir|=XDecreasing;
+ dX=x1-x2;
+ }
+ else
+ dX=x2-x1;
+
+ /* Check for dX>dY */
+ if (dY>dX)
+ { /* No then swap */
+ int temp=dX;
+ dX=dY;
+ dY=temp;
+ dir|=YMajor;
+ }
+
+ WaitGEfifo();
+ if (CurrentForegroundMix!=LineForegroundMix)
+ {
+ SetForegroundMix(LineForegroundMix);
+ CurrentForegroundMix=LineForegroundMix;
+ }
+ SetForeground(color);
+
+ /* Now dX > dY > 0 and all the flags for the octant are calculated */
+ SetXYLocation(x1,y1);
+ SetLineSteps(dY,dX);
+ SetErrAndLen(dY,dX);
+ SetDrawFlags(dir);
+ DoBresenhamLine();
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the mask used for stipple lines. @x{DrawStippleLine}.@p
+ I'm not sure about it so here is my guess: TGUI9440 have a 16 bits
+register (GER44,GER45) to set the mask used for patterned lines so I guess
+that's this function is to setup this value.@p
+
+***************************************************************************/
+
+void SetLineStipple(AF_DRIVER *af, unsigned short stipple)
+{
+ WaitGEfifo();
+ SetPenStyleMask(stipple);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the repeat counter for the mask used in stipple lines.
+@x{DrawStippleLine}.@p
+ I'm not sure about it so here is my guess: TGUI9440 have an 8 bits
+register (GER47) to set the scale of the pattern for patterned lines. A value
+of 0 means that each bit in the pattern is 1 dot, a value of 1 expands
+each pixel to 2 dots and so on.@p
+
+***************************************************************************/
+
+void SetLineStippleCount(AF_DRIVER *af, unsigned long count)
+{
+ WaitGEfifo();
+ SetStyleMaskRepeatCount(count);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Draws a stipple line (patterned, dotted). SetLineStipple sets the pattern
+used and SetLineStippleCount the scale. @x{SetLineStipple}.
+@x{SetLineStippleCount}.@p
+ Note: This function doesn't call drawline, it is almost the same code
+repeated. That's to increase speed because in this way I can make the
+Bresenham parameters calculation in parallel with the GE.
+
+***************************************************************************/
+
+void DrawStippleLine(AF_DRIVER *af, unsigned long foreColor,
+ unsigned long backColor, fixed x1, fixed y1,
+ fixed x2, fixed y2)
+{
+ int dX,dY,dir=PatternedLines | PatFromDisplay | SourceDataDisplay;
+
+ /* round coordinates from fixed point to integer */
+ x1=(x1+0x8000)>>16;
+ y1=((y1+0x8000)>>16)+af_y;
+ x2=(x2+0x8000)>>16;
+ y2=((y2+0x8000)>>16)+af_y;
+
+ /* Check if dY is positive */
+ if (y1>y2)
+ { /* No then reverse Y direction */
+ dir|=YDecreasing;
+ dY=y1-y2;
+ }
+ else
+ dY=y2-y1;
+
+ /* Check if dX is positive */
+ if (x1>x2)
+ { /* No then reverse Y direction */
+ dir|=XDecreasing;
+ dX=x1-x2;
+ }
+ else
+ dX=x2-x1;
+
+ /* Check for dX>dY */
+ if (dY>dX)
+ { /* No then swap */
+ int temp=dX;
+ dX=dY;
+ dY=temp;
+ dir|=YMajor;
+ }
+
+ WaitGEfifo();
+ if (CurrentForegroundMix!=LineForegroundMix)
+ {
+ SetForegroundMix(LineForegroundMix);
+ CurrentForegroundMix=LineForegroundMix;
+ }
+ SetForeground(foreColor);
+ SetBackground(backColor);
+
+ /* Now dX > dY > 0 and all the flags for the octant are calculated */
+ SetXYLocation(x1,y1);
+ SetLineSteps(dY,dX);
+ SetErrAndLen(dY,dX);
+ SetDrawFlags(dir);
+ DoBresenhamLine();
+}
+
+void SetMix(AF_DRIVER *af, long foreMix, long backMix)
+{
+ uchar af_fore_mix=0;
+ uchar af_back_mix=0;
+
+ /* Limit the values to my range */
+ af_fore_mix=foreMix & 0x1F;
+
+ if (backMix==0)
+ af_back_mix=af_fore_mix;
+ else
+ af_back_mix=backMix & 0x1F;
+
+ /* Foreground mix used by lines and pattern fills */
+ LineForegroundMix=ROPEquiv[af_fore_mix];
+ LineForegroundMixToS=ROPImageEquiv[af_fore_mix];
+ /* 9440 doesn't have Background mixing but I make it in 2 steps */
+ UsesBackMix=(af_back_mix!=af_fore_mix);
+ BackMix=ROPEquiv[af_back_mix];
+ DontMakeBackMix=(BackMix==ROP_D);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ 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)
+{
+ WaitGEfifo();
+ if (CurrentForegroundMix!=LineForegroundMix)
+ {
+ SetForegroundMix(LineForegroundMix);
+ CurrentForegroundMix=LineForegroundMix;
+ }
+ SetForeground(color);
+ SetDrawFlags(SolidDrawing | PatMono);
+ SetXYLocation(left,top+af_y);
+ SetDimensions(width-1,height-1);
+ DoBlit();
+}
+
+#ifdef __cplusplus
+extern "C" void DrawRawRect(unsigned long color, long left, long top, long width, long height);
+#endif
+// Internally used to clean the screen
+void DrawRawRect(unsigned long color, long left, long top, long width, long height)
+{
+ WaitGEfifo();
+ if (CurrentForegroundMix!=LineForegroundMix)
+ {
+ SetForegroundMix(LineForegroundMix);
+ CurrentForegroundMix=LineForegroundMix;
+ }
+ SetForeground(color);
+ SetDrawFlags(SolidDrawing | PatMono);
+ SetXYLocation(left,top+af_y);
+ SetDimensions(width,height);
+ DoBlitDontWait();
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ 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)
+{
+ unsigned mode=SolidDrawing | PatMono;
+ int w;
+
+ if (x1?*/DrawPattRect(af,foreColor,backColor,x1,y,x2-x1,1);
+ else if (x2 < x1)
+ DrawPattRect(af,foreColor,backColor,x2,y,x1-x2,1);
+ return;
+ }
+
+ if (x1left && dstLefttop && dstTopy+af_y;
+ /* scan-convert the trapezoid */
+ while (trap->count--)
+ {
+ /* Convert X values to ints rounding */
+ ix1=(trap->x1+0x8000)>>16;
+ ix2=(trap->x2+0x8000)>>16;
+
+ if (ix2x1+=trap->slope1;
+ trap->x2+=trap->slope2;
+ y++;
+ }
+ trap->y=y-af_y;
+}
+
+
+unsigned cur_hot_x,cur_hot_y;
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the hardware cursor shape.
+
+// ToDo split it in various
+
+***************************************************************************/
+
+void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor)
+{
+ int i;
+ unsigned long *p=(unsigned long *)pCursorPat;
+
+ #ifndef WAITTILLIDLE_NOT_NEEDED
+ if (IsAceleratorOn)
+ WaitGE();
+ #endif
+ if (HaveDoubleScan)
+ {
+ if (af_bpp==8)
+ {
+ for (i=0; i<32; i++)
+ {
+ p[i*8+4]=p[i*8+0]=~cursor->andMask[i];
+ p[i*8+5]=p[i*8+1]=cursor->xorMask[i];
+ p[i*8+2]=p[i*8+6]=0xFFFFFFFF;
+ p[i*8+3]=p[i*8+7]=0;
+ }
+ }
+ else
+ {
+ for (i=0; i<32; i++)
+ {
+ p[i*8+4]=p[i*8+0]=~cursor->andMask[i];
+ p[i*8+5]=p[i*8+1]=cursor->xorMask[i] ^ cursor->andMask[i];
+ p[i*8+2]=p[i*8+6]=0xFFFFFFFF;
+ p[i*8+3]=p[i*8+7]=0;
+ }
+ }
+ }
+ else
+ {
+ if (af_bpp==8)
+ {
+ for (i=0; i<32; i++)
+ {
+ p[i*2]=~cursor->andMask[i];
+ p[i*2+1]=cursor->xorMask[i];
+ }
+ }
+ else
+ {
+ for (i=0; i<32; i++)
+ {
+ p[i*2]=~cursor->andMask[i];
+ p[i*2+1]=cursor->xorMask[i] ^ cursor->andMask[i];
+ }
+ }
+ }
+ cur_hot_x=cursor->hotx;
+ cur_hot_y=cursor->hoty;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the hardware cursor position.
+
+***************************************************************************/
+
+void SetCursorPos(AF_DRIVER *af, long x, long y)
+{
+ x-=cur_hot_x;
+ y-=cur_hot_y;
+
+ if (HaveDoubleScan)
+ y*=2;
+ /* Allow small negative coordinates moving inside the cursor, Allegro needs
+ it */
+ if (y<0)
+ {
+ WriteCRT(0x47,-y);
+ y=0;
+ }
+ else
+ WriteCRT(0x47,0);
+ if (x<0)
+ {
+ WriteCRT(0x46,-x);
+ x=0;
+ }
+ else
+ WriteCRT(0x46,0);
+ WriteCRT(0x40,x);
+ WriteCRT(0x41,x>>8);
+ WriteCRT(0x42,y);
+ WriteCRT(0x43,y>>8);
+}
+
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the hardware cursor color.@p
+ Not supported by TGUI9440, I think 968x adds some registers for it.
+
+***************************************************************************/
+
+void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green,
+ unsigned char blue)
+{
+ /* I disabled it because it normally mess the things.
+ if (af_bpp==8)
+ {
+ outportb(WriteDataAddress,0);
+ outportb(PaletteDataRegister,red/4);
+ outportb(PaletteDataRegister,green/4);
+ outportb(PaletteDataRegister,blue/4);
+ }
+ */
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Turns the hardware cursor on or off.
+
+***************************************************************************/
+
+void ShowCursor(AF_DRIVER *af, long visible)
+{
+ unsigned mode=visible ? 0x80 : 0;
+ mode|=HaveDoubleScan ? 1 : 0;
+ WriteCRT(0x50,mode);
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ C-callable bank switch function.
+
+***************************************************************************/
+
+void SetBank(AF_DRIVER *af, long bank)
+{
+ #ifdef INCLUDE_OLD_INERTIA_STUFF
+ afCurBank=bank;
+ #endif
+ /* TGUI supports individual banks for read & write so we must set both */
+ outportw(DestinationSegmentAddress,bank | (bank<<8));
+}
+
+/* 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, %al
+ movb %dl, %ah
+ movw $0x03D8, %dx
+ outw %ax, %dx
+ popl %edx
+ popl %eax
+ ret
+
+_SetBank32End:
+");
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Palette setting routine. Palette values are in 8 bits format because some
+boards support 8 bits DAC and not only 6 bits.
+
+***************************************************************************/
+
+void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT)
+{
+ int i;
+
+ if (waitVRT)
+ WaitVRT();
+
+ outportb(WriteDataAddress,index);
+ for (i=0; i=0)
+ {
+ addr=(((y+af_visible_page*af_height)*af_width_bytes)+(x*af_bytespp));
+ PEL=addr & 3;
+ addr/=4;
+
+ /* Wait until we have a retrace (H or V) */
+ while (inportb(0x3DA) & 1);
+
+ /* bits 0 to 7 are in 3D5.0D */
+ WriteCRT(0x0D,addr);
+ /* bits 8 to 15 are in 3D5.0C */
+ WriteCRT(0x0C,addr>>8);
+
+ /* bit 16 is in 3D5.1E.b5, b7 must be 1. The last is made by
+ SetVideoMode */
+ temp=ReadCRT(0x1E);
+ if (addr & 0x10000)
+ temp|=0x20;
+ else
+ temp&=0xDF;
+ WriteCRT(0x1E,temp);
+
+ /* bits 17 and 18 are bits 0 and 1 of 3D5.27 */
+ temp=ReadCRT(0x27) & 0xFC;
+ WriteCRT(0x27,temp | (addr>>17));
+
+ /* Wait a vertical retrace */
+ if (waitVRT)
+ while (!(inportb(0x3DA) & 8));
+ /* Set PEL register */
+ outportb(0x3C0,0x13 | 0x20);
+ outportb(0x3C0,PEL);
+ }
+
+ af_scroll_x=x;
+ af_scroll_y=y;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets which buffer is being drawn onto, for use in multi buffering
+systems (not used by Allegro).@p
+ I took it from the prototype driver and seems to be totally independent
+of the board.
+
+***************************************************************************/
+
+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->OriginOffset=af_width_bytes*af_height*index;
+
+ if (af->OffscreenOffset)
+ {
+ af->OffscreenStartY-=af_active_page*af_height;
+ af->OffscreenEndY-=af_active_page*af_height;
+ }
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets which buffer is displayed on the screen, for use in multi buffering
+systems (not used by Allegro).@p
+ Copied from the prototype driver.
+
+***************************************************************************/
+
+void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT)
+{
+ af_visible_page=index;
+
+ SetDisplayStart(af, af_scroll_x, af_scroll_y, waitVRT);
+}
+
+
+#define DontBeSillyClearingMoreThanOnes
+/**[txh]********************************************************************
+
+ Description:
+ 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)
+{
+ unsigned i;
+ int mode=Mode,bpl=1;
+ VideoModeStr *info;
+ unsigned sX,sY;
+
+ /* Report error if the mode is outside the range */
+ if ((mode<=0) || (mode>NumSupportedVideoModes))
+ return -1;
+
+ info=SupportedVideoModes[mode-1];
+
+ /* clear the structure to zero */
+ for (i=0; iAttributes=afHaveVirtualScroll |
+ afHaveBankedBuffer | afHaveLinearBuffer
+ /* Not sure if that's VBE compliant */
+ | afHaveHWCursor
+ /* TGUI supports ROP3 */
+ | afHaveROP2
+ /* none of my modes is VGA */
+ | afNonVGAMode;
+
+ sX=info->hDisplay;
+ sY=info->vDisplay;
+ /* Transfer some bits from my structure */
+ /* I doubt the following too are OK because other drivers reports it in
+ a different way */
+ if (info->flags & DoubleScan)
+ {
+ modeInfo->Attributes|=afHaveDoubleScan;
+ sY>>=1;
+ }
+ if (info->flags & Interlaced)
+ {
+ modeInfo->Attributes|=afHaveInterlaced;
+ sY<<=1;
+ }
+ if (info->flags & HaveAccel2D)
+ modeInfo->Attributes|=afHaveAccel2D;
+
+ modeInfo->XResolution=sX;
+ modeInfo->YResolution=sY;
+ switch (ExtractBPP(info->flags))
+ {
+ case is8BPP:
+ modeInfo->BitsPerPixel=8;
+ modeInfo->MaxScanLineWidth=4096;
+ #ifndef DontBeSillyClearingMoreThanOnes
+ modeInfo->RedMaskSize = 0;
+ modeInfo->RedFieldPosition = 0;
+ modeInfo->GreenMaskSize = 0;
+ modeInfo->GreenFieldPosition = 0;
+ modeInfo->BlueMaskSize = 0;
+ modeInfo->BlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = 0;
+ modeInfo->RsvdFieldPosition = 0;
+ #endif
+ bpl=1;
+ break;
+ case is15BPP:
+ modeInfo->BitsPerPixel=15;
+ modeInfo->MaxScanLineWidth=2048;
+ modeInfo->RedMaskSize = 5;
+ modeInfo->RedFieldPosition = 10;
+ modeInfo->GreenMaskSize = 5;
+ modeInfo->GreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = 5;
+ modeInfo->BlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = 1;
+ modeInfo->RsvdFieldPosition = 15;
+ bpl=2;
+ break;
+ case is16BPP:
+ modeInfo->BitsPerPixel=16;
+ modeInfo->MaxScanLineWidth=2048;
+ modeInfo->RedMaskSize = 5;
+ modeInfo->RedFieldPosition = 11;
+ modeInfo->GreenMaskSize = 6;
+ modeInfo->GreenFieldPosition = 5;
+ modeInfo->BlueMaskSize = 5;
+ modeInfo->BlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = 0;
+ modeInfo->RsvdFieldPosition = 0;
+ bpl=2;
+ break;
+ case is24BPP:
+ modeInfo->BitsPerPixel=24;
+ modeInfo->MaxScanLineWidth=1360;
+ modeInfo->RedMaskSize = 8;
+ modeInfo->RedFieldPosition = 16;
+ modeInfo->GreenMaskSize = 8;
+ modeInfo->GreenFieldPosition = 8;
+ modeInfo->BlueMaskSize = 8;
+ modeInfo->BlueFieldPosition = 0;
+ modeInfo->RsvdMaskSize = 0;
+ modeInfo->RsvdFieldPosition = 0;
+ bpl=3;
+ break;
+ }
+
+
+ /* available pages of video memory */
+ modeInfo->MaxBuffers=AvailableRAM/(info->minBytesPerScan*sY);
+ if (modeInfo->MaxBuffers>1)
+ modeInfo->Attributes|=afHaveMultiBuffer;
+
+ /* maximum virtual scanline length in both bytes and pixels. How wide
+ * this can go will very much depend on the card.
+ */
+ /* Here I put the maximun of the chip, if the board doesn't have enough
+ RAM that isn't true */
+ modeInfo->MaxBytesPerScanLine=4096;
+
+ modeInfo->LinBytesPerScanLine=
+ modeInfo->BytesPerScanLine = info->minBytesPerScan;
+ modeInfo->LinMaxBuffers =
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->LinRedMaskSize = modeInfo->RedMaskSize;
+ modeInfo->LinRedFieldPosition = modeInfo->RedFieldPosition;
+ modeInfo->LinGreenMaskSize = modeInfo->GreenMaskSize;
+ modeInfo->LinGreenFieldPosition = modeInfo->GreenFieldPosition;
+ modeInfo->LinBlueMaskSize = modeInfo->BlueMaskSize;
+ modeInfo->LinBlueFieldPosition = modeInfo->BlueFieldPosition;
+ modeInfo->LinRsvdMaskSize = modeInfo->RsvdMaskSize;
+ modeInfo->LinRsvdFieldPosition = modeInfo->RsvdFieldPosition;
+
+ /* Shawn says:
+ I'm not sure exactly what these should be: Allegro doesn't use them */
+ /* Here I put the maximun clock the board can generate according to the
+ specifications. The 15/16 bpp modes uses a "character clock divider" I
+ think that's what Trident use to call a pixel (%2) and 24 bpp uses %3.
+ The manual have a funny bug because they say the other value can be
+ used to make %0 (-> infinite) ;-))) */
+ modeInfo->MaxPixelClock = 140000000/bpl;
+ #ifndef DontBeSillyClearingMoreThanOnes
+ /* Don't have any idea about it */
+ modeInfo->VideoCapabilities = 0;
+ /* Some boards support zooming nVidia RIVA 128 can do it and I think some
+ old Tseng Labs boards too */
+ modeInfo->VideoMinXScale = 0;
+ modeInfo->VideoMinYScale = 0;
+ modeInfo->VideoMaxXScale = 0;
+ modeInfo->VideoMaxYScale = 0;
+ #endif
+
+ return 0;
+}
+
+/******************** Video Clock calculation algorithm ********************/
+/*****************************************************************************
+
+ Some info about 9440:
+ VClk (Dot clock)
+ Main PLL:
+
+ F=(N+8)/(M+2)*14.31818
+ N: 0..121
+ M: 0..31
+ 49.97 < F < 140.03 That means 50..140 MHz
+
+ Then we have the following dividers:
+ %1 and %2 in the PLL.
+ %1, %1.5, %2 and %4 in the CRTC
+ So we have: %1, %1.5, %2, %3, %4 and %8
+ Giving a range: 6.25..140 MHz
+
+ PClk is the VClk %1, %2 or %3 according to the pixel width (1, 2 or 3 bytes).
+
+ So as we get the PClk as parameter we must know the video mode to calculate
+the VClk.
+
+*****************************************************************************/
+
+/* Reference frecuency %1, %1.5, etc. */
+#define NUM_REFS 6
+static
+unsigned fR[]={14318180,9545453,7159090,4772727,3579545,1789773};
+/* Look how fR[3] is the XT clock and fR[4] is the NTSC color sub-carrier */
+
+#define ClkErrVal ((unsigned)-1)
+
+/**[txh]********************************************************************
+
+ Description:
+ This routine calculates the closest frecuency to fx that we can achieve
+with the 9440 PLL. The values to program the chip are stored in VClkReg and
+Divider.
+
+ Return:
+ The closest available frecuency or (unsigned)-1 if the value is outside
+the range.
+
+***************************************************************************/
+
+static
+unsigned FindClosestVClk(unsigned fx, unsigned *VClkReg, unsigned *Divider)
+{
+ unsigned M,N,bM=0,bN=0,bDiv=0,fr;
+ int div,dif,minDif=140000000,i;
+ unsigned f,bf=0;
+
+ /* Reject values clearly outside the range */
+ if (fx<6200000 || fx>140500000)
+ return ClkErrVal;
+
+ /* We will try the 6 dividers and the 32 values of M => 192 values */
+ for (div=0; div129)
+ break;
+ /* Now try N and N+1 (384 values), N will give a frequency below
+ fx and N+1 above fx */
+ for (i=0; i<2; i++)
+ {
+ /* Calculate f */
+ f=(N*fr)/M;
+ /* Calculate |delta f| */
+ dif=f-fx;
+ if (dif<0)
+ dif=-dif;
+ /* Store the minimun */
+ if (dif 1 byte, 16 bpp => 2 bytes, etc.) and we in fact calculate the
+video clock ("Dot" clock I guess) so we must multiply by the pixel size
+first.@p
+
+ Returns:
+ The closest value available for the board or (unsigned)-1 if the value is
+outside the range.
+
+***************************************************************************/
+
+long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock)
+{
+ VideoModeStr *info;
+ unsigned a1,a2,closest;
+ int Bpp;
+
+ /* Filter the mode number and reject invalid modes */
+ mode&=0x3FF;
+ if ((mode<=0) || (mode>NumSupportedVideoModes))
+ return ClkErrVal;
+
+ /* Find the number of bytes per pixel */
+ info=SupportedVideoModes[mode-1];
+ Bpp=tBytesPerPixel[ExtractBPP(info->flags)];
+
+ /* Convert to Video Clock units */
+ pixelClock*=Bpp;
+
+ /* Call the 9440 routine */
+ closest=FindClosestVClk(pixelClock,&a1,&a2);
+ if (closest==ClkErrVal)
+ return closest;
+
+ return closest/Bpp;
+}
+
+#define afVM_DontPalette 0x80000000
+#define afVM_DontClear 0x8000
+#define afVM_LFB 0x4000
+#define afVM_MultiBuffer 0x2000
+#define afVM_VirtualScrl 0x1000
+#define afVM_UseRefresh 0x0800
+#define afVM_Stereo 0x0400
+
+uchar DefaultVGAPalette[768]={
+0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
+0x00,0x2A,0x2A,0x15,0x00,0x2A,0x2A,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
+0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
+0x00,0x00,0x00,0x05,0x05,0x05,0x08,0x08,0x08,0x0B,0x0B,0x0B,0x0E,0x0E,0x0E,0x11,
+0x11,0x11,0x14,0x14,0x14,0x18,0x18,0x18,0x1C,0x1C,0x1C,0x20,0x20,0x20,0x24,0x24,
+0x24,0x28,0x28,0x28,0x2D,0x2D,0x2D,0x32,0x32,0x32,0x38,0x38,0x38,0x3F,0x3F,0x3F,
+0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x3F,0x3F,
+0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,
+0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,
+0x00,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,
+0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,
+0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,
+0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
+0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
+0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
+0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
+0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
+0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
+0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
+0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
+0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
+0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
+0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
+0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
+0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
+0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
+0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
+0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
+0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
+0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
+0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
+0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
+0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
+0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
+0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
+0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
+0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
+0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
+0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
+0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
+0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
+0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
+0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
+0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
+0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
+0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
+0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
+0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};
+
+/**[txh]********************************************************************
+
+ Description:
+ Sets the video mode. This function have various features, be careful.@p
+ Mode is a 32 bits value, and not 16 bits as the first drafts propposed.
+Because a some nasty reasons isn't just a mode number but some sort of flags
+plus mode number. The lower 10 bits are the video mode number the rest of
+the bits have the following meaning:@p
+
+ 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.@p
+
+Most of them are self-explanatory, and others aren't very clear yet.@p
+The virtual screen size is requested by the virtualX/Y pair the driver will
+set a screen of at least this size, if isn't posible will return error. Note
+that the actual size could be greater. For this reason bytesPerLine is filled
+with the actual X virtual size (stride?).@p
+You can request more than one buffer indicating it in numBuffers, if the RAM
+isn't enough the driver will return error.@p
+Perhaps the hardest parameter to understand is crtc. This parameter provides
+a mechanism to allow setting the refresh rate and centering the screen. The
+mechanism is incomplet and SciTech people complements it with OEM extentions,
+I asked to make these extentions official and Kendall said he will consider
+it for Nucleus. Anyways, this pointer will be used by the driver if you use
+the 0x0800 flag, the members of the structure are:@p
+
+unsigned short HorizontalTotal: Total pixels, visible and not visible.@*
+unsigned short HorizontalSyncStart: Pixel where the horizontal sync pulse
+starts.@*
+unsigned short HorizontalSyncEnd: End of the pulse.@*
+unsigned short VerticalTotal: Total lines, visible and not.@*
+unsigned short VerticalSyncStart: Vertical sync pulse start.@*
+unsigned short VerticalSyncEnd: End of the pulse.@*
+unsigned char Flags: Various flags see below.@*
+unsigned int PixelClock: Desired pixel clock, the driver will use the
+closest available so you must check it with GetClosestPixelClock.
+@x{GetClosestPixelClock}.@*
+unsigned short RefreshRate: Just ignore it is for very old controllers that
+have some specific crtc register values for each mode.@*
+unsigned short NumBuffers: That's here only for compatibility issues related
+to VBE/AF 1.0.@p
+
+The possible flags are:@p
+
+afDoubleScan (0x0001) Enable double scanned mode.@*
+afInterlaced (0x0002) Enable interlaced mode.@*
+afHSyncNeg (0x0004) Horizontal sync is negative.@*
+afVSyncNeg (0x0008) Vertical sync is negative.@p
+
+As you can see only the X/Y resolution is set by the driver and you control
+all the rest.@p
+To use it you must first find information about the monitor (asking the user
+or using DDC?), then calculate the total and sync positions with the VESA
+GTF formula and the aid of GetClosestPixelClock and finally pass these values
+to the driver.@p
+
+Important:@p
+1) I don't care about LFB that's on all the time.@*
+2) I expanded the short mode to unsigned mode because MGL 4.05 does it.@*
+3) I added a propietary flag: 0x80000000: Don't set the palette. I think it
+will be replaced by some OEM extention, avoid using it.@p
+
+***************************************************************************/
+
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
+ long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ int clear = ((mode & afVM_DontClear)==0);
+ int putPal = ((mode & afVM_DontPalette)==0);
+ int CRTCValid = ((mode & afVM_UseRefresh)!=0) && crtc;
+ unsigned used_vram,af_width,sX,sY;
+ int bpl,nbpp,Bpp;
+ VideoModeStr *info,byApp;
+
+ /* reject anything with hardware stereo */
+ if (mode & afVM_Stereo)
+ return -1;
+
+ afCurrentMode=mode;
+ /* mask off the other flag bits */
+ mode&=0x3FF;
+
+ if ((mode<=0) || (mode>NumSupportedVideoModes))
+ return -1;
+
+ info=SupportedVideoModes[--mode];
+
+ sX=info->hDisplay;
+ sY=info->vDisplay;
+ if (info->flags & DoubleScan)
+ sY>>=1;
+ if (info->flags & Interlaced)
+ sY<<=1;
+
+ /* Now choose the right virtual width */
+ nbpp=ExtractBPP(info->flags);
+ Bpp=tBytesPerPixel[nbpp];
+ bpl=GetBestPitchFor(MAX(virtualX,(long)sX),Bpp);
+ if (bpl<0)
+ return -1;
+ *bytesPerLine=bpl;
+
+ /* store info about the current mode */
+ af_bpp = tBitsPerPixel[nbpp];
+ af_bytespp = Bpp;
+ af_width_bytes = *bytesPerLine;
+ af_height = MAX((long)sY,virtualY);
+ af_visible_page= 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_y = 0;
+ af_width = bpl/Bpp;
+ afCurrentBank = 0;
+
+ /* return framebuffer dimensions to the application */
+ af->BufferEndX = af_width_bytes/af_bytespp-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram=af_width_bytes*af_height*numBuffers;
+
+ if (used_vram>AvailableRAM)
+ return -1;
+
+ if (AvailableRAM-used_vram>=af_width_bytes)
+ {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = AvailableRAM/af_width_bytes-1;
+ }
+ else
+ {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ /* Set the fore/back mixing to the default values */
+ UsesBackMix=DontMakeBackMix=0;
+ BackMix=LineForegroundMix=CurrentForegroundMix=ROP_P;
+ LineForegroundMixToS=ROP_S;
+
+ /* Look if the application is suggesting the video mode refresh rate */
+ if (CRTCValid)
+ {
+ unsigned closest,VClk,Divider;
+
+ byApp.minBytesPerScan = info->minBytesPerScan;
+ /* Copy the values from the CRTC structure */
+ byApp.hDisplay = sX;
+ byApp.hTotal = crtc->HorizontalTotal;
+ byApp.hSyncStart = crtc->HorizontalSyncStart;
+ byApp.hSyncEnd = crtc->HorizontalSyncEnd;
+ byApp.vDisplay = sY;
+ byApp.vTotal = crtc->VerticalTotal;
+ byApp.vSyncStart = crtc->VerticalSyncStart;
+ byApp.vSyncEnd = crtc->VerticalSyncEnd;
+ byApp.flags = info->flags & InternalMask;
+ if (crtc->Flags & afDoubleScan)
+ {
+ byApp.flags|=DoubleScan;
+ byApp.vDisplay<<=1;
+ }
+ if (crtc->Flags & afInterlaced)
+ {
+ byApp.flags|=Interlaced;
+ byApp.vDisplay>>=1;
+ }
+ if (crtc->Flags & afHSyncNeg)
+ byApp.flags|=NHSync;
+ if (crtc->Flags & afVSyncNeg)
+ byApp.flags|=NVSync;
+ closest=FindClosestVClk(crtc->PixelClock*Bpp,&VClk,&Divider);
+ if (closest==ClkErrVal)
+ return -1;
+ byApp.ClockType =Divider;
+ byApp.ClockValLow =VClk;
+ byApp.ClockValHigh=VClk>>8;
+ /* The following values are filled by the app. and ignored here
+ crtc->RefreshRate=closest*100/byApp.vTotal/byApp.hTotal;
+ crtc->NumBuffers=AvailableRAM/(info->minBytesPerScan*sY);*/
+ SetVideoModeH(&byApp,af_width,af_bpp);
+ }
+ else
+ SetVideoModeH(info,af_width,af_bpp);
+
+ /* 8 bpp palette */
+ if (af_bpp==8 && putPal)
+ RPF_SetPalRange(DefaultVGAPalette,0,256);
+
+ /* All the routines sets it only if change so we must start we a known
+ state or it could hang */
+ SetForegroundMix(CurrentForegroundMix);
+
+ IsAceleratorOn=info->flags & HaveAccel2D ? 1 : 0;
+ if (clear)
+ {
+ if (IsAceleratorOn)
+ /* If we have the accelerator clean the screen without the CPU */
+ DrawRawRect(0,0,0,af_width-1,af_height-1);
+ else
+ {
+ unsigned i;
+ for (i=used_vram/4; i; --i)
+ Screenl[i]=0;
+ Screenl[i]=0;
+ }
+ }
+
+ /* Hardware cursor initialization */
+ /* Shape offset in VRAM */
+ WriteCRT(0x44,CursorPat);
+ WriteCRT(0x45,CursorPat>>8);
+ /* Offset inside the shape (X,Y) */
+ WriteCRT(0x46,0);
+ WriteCRT(0x47,0);
+ /* In double scan modes the cursor must be adjusted */
+ HaveDoubleScan=info->flags & DoubleScan ? 1 : 0;
+
+ if (IsAceleratorOn)
+ {
+ af->DrawScan = DrawScan;
+ af->DrawScanList = DrawScanList;
+ af->DrawPattScan = DrawPattScan;
+ af->DrawPattScanList = DrawPattScanList;
+ af->DrawColorPattScan = DrawColorPattScan;
+ af->DrawColorPattScanList= DrawColorPattScanList;
+ af->DrawRect = DrawRect;
+ af->DrawPattRect = DrawPattRect;
+ af->DrawColorPattRect = DrawColorPattRect;
+ af->DrawLine = DrawLine;
+ af->DrawTrap = DrawTrap;
+ /* Dotted (Stipple) lines */
+ /* I'm not sure about the behavior of these functions, I just implemented
+ the functionallities found in TGUI9440. I guess they are the same
+ needed for the driver, after all Trident was in the VBE/AF desing */
+ af->SetLineStipple = SetLineStipple;
+ af->SetLineStippleCount = SetLineStippleCount;
+ af->DrawStippleLine = DrawStippleLine;
+ af->BitBlt = BitBlt;
+ af->BitBltSys = BitBltSys;
+ af->SrcTransBlt = SrcTransBlt;
+ af->SrcTransBltSys = SrcTransBltSys;
+ af->PutMonoImage = PutMonoImage;
+
+ /* Routines to control the access to the video ram */
+ af->WaitTillIdle = WaitTillIdle;
+ /* I'm not sure about these 2, seems that I don't need it by Kendall says
+ in an e-mail that normally EnableDirectAccess is the same as
+ WaitTillIdle so I implemented it in this way */
+ /* I commented it because VBE/AF 1.0 draft says they are optional and
+ WaitTillIdle requered, so if I provide WaitTillIdle must be enough.
+ af->EnableDirectAccess = EnableDirectAccess;
+ af->DisableDirectAccess = DisableDirectAccess;*/
+
+ }
+ else
+ { /* 24 bpp doesn't have it :-( */
+ af->DrawScan = NULL;
+ af->DrawScanList = NULL;
+ af->DrawPattScan = NULL;
+ af->DrawPattScanList = NULL;
+ af->DrawRect = NULL;
+ af->DrawPattRect = NULL;
+ af->DrawLine = NULL;
+ af->BitBlt = NULL;
+ af->DrawColorPattScan = NULL;
+ af->DrawColorPattScanList= NULL;
+ af->DrawColorPattRect = NULL;
+ af->SetLineStipple = NULL;
+ af->SetLineStippleCount = NULL;
+ af->DrawStippleLine = NULL;
+ af->BitBlt = NULL;
+ af->BitBltSys = NULL;
+ af->SrcTransBlt = NULL;
+ af->SrcTransBltSys = NULL;
+ af->PutMonoImage = NULL;
+ af->DrawTrap = NULL;
+ af->WaitTillIdle = NULL;
+ }
+
+ /* Some GER values */
+ /* Patterned lines: Pattern cleared, counters reseted */
+ Putl(0x44,0);
+
+ return 0;
+}
+
+#ifdef INCLUDE_OLD_INERTIA_STUFF
+#include "oldinert.h"
+#endif
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Returns to text mode, shutting down the accelerator hardware.
+
+***************************************************************************/
+
+void RestoreTextMode(AF_DRIVER *af)
+{
+ SetTextModeVGA();
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Provides direct access to the video RAM. That's needed for boards where
+the accelerator blocks the use of the video RAM.@p
+ TGUI9440 does it only during the Blit operations so in my case I simply
+do a wait until de Graphics Engine finished your job. Note that this routine
+is here just for testing because isn't needed and isn't reported.
+
+ Example:
+
+ EnableDirectAccess(af);
+ .... Draw to the screen ....
+ DisableDirectAccess(af);
+
+***************************************************************************/
+
+void EnableDirectAccess(AF_DRIVER *af)
+{
+ WaitGE();
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Disables the direct access to the video RAM. That's needed for boards
+where the accelerator blocks the use of the video RAM.@p
+ TGUI9440 does it only during the Blit operations so in my case this
+function does nothing. Note that this routine is here just for testing
+because isn't needed and isn't reported.
+
+***************************************************************************/
+
+void DisableDirectAccess(AF_DRIVER *af)
+{
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Waits until the accelerator finished your job. That's a very important
+function. Suppose you want to draw over a rectangle made with DrawRect, how
+can you be sure you won't draw under it? Waiting until the accelerator
+finished your job.@p
+ What I don't fully understand is the need of both:
+Enable/DisableDirectAccess and WaitTillIdle. I saw an e-mail by Kendall
+tallking about it.@p
+ The TGUI9440 waits until the Graphic Engine finished all the jobs.
+
+***************************************************************************/
+
+void WaitTillIdle(AF_DRIVER *af)
+{
+ WaitGE();
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ Vendor-specific extension hook: we don't provide any.
+
+***************************************************************************/
+
+int ExtStub()
+{
+ return 0;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ 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)
+{
+ int bus_id;
+
+ /* It looks silly: I must have access to the PCI registers! */
+ if (!FindPCIDevice(af->PCIDeviceID,af->PCIVendorID,0,&bus_id))
+ return -1;
+
+ af->AvailableModes=SupportedVideoModesNums;
+
+ af->Attributes = afHaveMultiBuffer | afHaveVirtualScroll |
+ afHaveBankedBuffer | afHaveLinearBuffer |
+ afHaveAccel2D | afHaveHWCursor |
+ afHaveROP2;
+
+ af->IOPortsTable=PortsTable;
+
+ /* 64Kb banking area */
+ af->BankedBasePtr=0xA0000;
+ af->BankSize=64;
+
+ af->LinearBasePtr=PCIReadLong(bus_id,0x10);
+ /* TGUI 9440 ever uses a 2Mb aperture */
+ af->LinearSize=2048;
+
+ /* 64Kb text mode area, I map the GER here */
+ af->IOMemoryBase[0]=0xB0000;
+ af->IOMemoryLen[0]=64;
+ /* That's the mapping for the GER, but as I need more space to
+ restore the text mode I simply map the whole text mode region */
+ /*af->IOMemoryBase[0]=0xB7F00;
+ af->IOMemoryLen[0]=1;
+ af->IOMemoryBase[1]=0xBFF00;
+ af->IOMemoryLen[1]=1;*/
+
+ /* 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->SetDisplayStart = SetDisplayStart;
+ af->SetActiveBuffer = SetActiveBuffer;
+ af->SetVisibleBuffer = SetVisibleBuffer;
+ af->GetDisplayStartStatus= GetDisplayStartStatus;
+ af->SetBank = SetBank;
+
+ af->SetPaletteData = SetPaletteData;
+
+ af->SetMix = SetMix;
+ af->Set8x8MonoPattern = Set8x8MonoPattern;
+ af->Set8x8ColorPattern = Set8x8ColorPattern;
+ af->Use8x8ColorPattern = Use8x8ColorPattern;
+
+ af->SetCursor = SetCursor;
+ af->SetCursorPos = SetCursorPos;
+ af->SetCursorColor = SetCursorColor;
+ af->ShowCursor = ShowCursor;
+
+ af->GetClosestPixelClock = GetClosestPixelClock;
+
+ #ifdef INCLUDE_OLD_INERTIA_STUFF
+ /* Inertia stuff */
+ af->GetConfigInfo = GetConfigInfo;
+ af->GetCurrentMode = GetCurrentMode;
+ af->SetVSyncWidth = SetVSyncWidth;
+ af->GetVSyncWidth = GetVSyncWidth;
+ af->GetBank = GetBank;
+ af->GetVisibleBuffer = GetVisibleBuffer;
+ af->GetDisplayStart = GetDisplayStart;
+ af->SetDisplayStartAddr = SetDisplayStartAddr;
+ af->IsVSync = IsVSync;
+ af->WaitVSync = WaitVSync;
+ af->GetActiveBuffer = GetActiveBuffer;
+ af->IsIdle = IsIdle;
+ #endif
+
+ /* ToDo
+ af->SaveRestoreState = NULL;
+ */
+
+ return 0;
+}
+
+
+/**[txh]********************************************************************
+
+ Description:
+ 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)
+{
+ int i;
+
+ MMIOBASE=(unsigned)(af->IOMemMaps[0])+0x7F00;
+ linearAddress=(unsigned long)af->LinearMem;
+ bankedAddress=(unsigned long)af->BankedMem;
+ TextModeMemory=(unsigned *)((unsigned)(af->IOMemMaps[0])+0x8000);
+ /* Now I can access the linear buffer and all the registers */
+ CaptureSVGAStart();
+ /* Find the amount of installed memory */
+ AvailableRAM=TestMemory();
+
+ /* Normalize the memory size, I had problem with intermediate sizes looks
+ like is impossible to detect 1.25 Mb. Trident's BIOS only reports 256K,
+ 512K, 1M or 2Mb it looks like a limitation of what we can detect */
+ if (AvailableRAM>=(1<<21))
+ AvailableRAM=1<<21;
+ else
+ if (AvailableRAM>=(1<<20))
+ AvailableRAM=1<<20;
+ else
+ if (AvailableRAM>=(1<<19))
+ AvailableRAM=1<<19;
+ else
+ if (AvailableRAM>=(1<<18))
+ AvailableRAM=1<<18;
+ else
+ return -1;
+
+ af->TotalMemory=AvailableRAM/1024; /* In Kb */
+
+ /* Reserve 2Kb of memory for patterns and harware cursor */
+ /* Monochromatic pattern */
+ /* I use 128 bytes aligment because in 16bpp that's required */
+ AvailableRAM-=128;
+ pMonoPattern=linearAddress+AvailableRAM;
+ MonoPattern=AvailableRAM>>6;
+ AvailableRAM-=128;
+ pInvMonoPattern=linearAddress+AvailableRAM;
+ InvMonoPattern=AvailableRAM>>6;
+ /* Hardware Cursor */
+ /* 32x32 (size) * 2 (planes) / 8 (packed) = 256 but 1K aligned */
+ AvailableRAM-=256+512;
+ pCursorPat=linearAddress+AvailableRAM;
+ CursorPat=AvailableRAM>>10;
+ /* 8 patterns of 8x8x2 bytes */
+ for (i=0; i<8; i++)
+ {
+ AvailableRAM-=128;
+ pColorPatterns[i]=linearAddress+AvailableRAM;
+ ColorPatterns[i]=AvailableRAM>>6;
+ }
+ SelectedColorPattern=ColorPatterns[0];
+
+ return 0;
+}
+
+
+/* FreeBEX:
+ * Returns an interface structure for the requested FreeBE/AF extension.
+ */
+void *FreeBEX(AF_DRIVER *af, unsigned long id)
+{
+ switch (id) {
+
+ default:
+ return NULL;
+ }
+}
+
+
+
diff --git a/tgui/drvhdr.c b/tgui/drvhdr.c
new file mode 100644
index 0000000..9dd7d61
--- /dev/null
+++ b/tgui/drvhdr.c
@@ -0,0 +1,45 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * VBE/AF driver header, used as input for DRVGEN.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+#include "vbeaf.h"
+
+
+
+AF_DRIVER drvhdr =
+{
+ "VBEAF.DRV", /* Signature */
+ 0x200, /* Version */
+ 0x100, /* DriverRev */
+ "FreeBE/AF TGUI9440 driver " FREEBE_VERSION, /* OemVendorName */
+ "This driver is free software", /* OemCopyright */
+ NULL, /* AvailableModes */
+ 0, /* TotalMemory */
+ 0, /* Attributes */
+ 0, /* BankSize */
+ 0, /* BankedBasePtr */
+ 0, /* LinearSize */
+ 0, /* LinearBasePtr */
+ 0, /* LinearGranularity */
+ NULL, /* IOPortsTable */
+ { NULL, NULL, NULL, NULL }, /* IOMemoryBase */
+ { 0, 0, 0, 0 }, /* IOMemoryLen */
+ 0, /* LinearStridePad */
+ 0x1023, /* PCIVendorID */
+ 0x9440, /* PCIDeviceID */
+ 0xFFFF, /* PCISubSysVendorID */
+ 0xFFFF, /* PCISubSysID */
+ 0 /* Checksum */
+};
+
diff --git a/tgui/font.h b/tgui/font.h
new file mode 100644
index 0000000..8844f2d
--- /dev/null
+++ b/tgui/font.h
@@ -0,0 +1,266 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/* Well, I guess the fonts are Copyrighted by Trident but if you use this
+ driver then you have a Trident card so I can't see any problem.
+ But don't use it for other driver without having clear if you can do it.
+*/
+
+uchar VGA8x16Font[256*16]={
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x99,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,
+0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
+0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
+0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
+0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x18,0x18,0xFF,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x0E,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+0x00,0x00,0xE6,0x66,0x6C,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0xE7,0xFF,0xDB,0xDB,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
+0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x6C,0x6C,0x38,0x38,0x6C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFF,0xC3,0x83,0x06,0x0C,0x18,0x30,0x61,0xC3,0xFF,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x3E,0x00,0x00,0x00,0x00,
+0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
+0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0xDC,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
+0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xE6,0xFF,0xDB,0xDB,0xDB,0xDB,0xDB,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
+0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x62,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,
+0x00,0x00,0xCC,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xCC,0xCC,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x66,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0xC6,0xC6,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x1B,0x7E,0xD8,0xDC,0x77,0x00,0x00,0x00,0x00,
+0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,
+0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+0x00,0xC6,0xC6,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0xC6,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00,
+0x00,0x00,0xC3,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0xFC,0x66,0x66,0x7C,0x62,0x66,0x6F,0x66,0x66,0x66,0xF3,0x00,0x00,0x00,0x00,
+0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xCE,0x93,0x06,0x0C,0x1F,0x00,0x00,
+0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9A,0x3F,0x06,0x0F,0x00,0x00,
+0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x33,0x66,0xCC,0x66,0x33,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xCC,0x66,0x33,0x66,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,
+0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
+0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,
+0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xDC,0xC6,0xC3,0xC3,0xC3,0xCE,0x00,0x00,0x00,0x00,
+0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x80,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x03,0x06,0x7E,0xCF,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,
+0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0xFF,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00,
+0x00,0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x18,0x00,0xFF,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
+0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x70,0x98,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
diff --git a/tgui/html.frt b/tgui/html.frt
new file mode 100644
index 0000000..7dfb614
--- /dev/null
+++ b/tgui/html.frt
@@ -0,0 +1,263 @@
+#
+# This file sets the behavior of the txh generator
+#
+# Lines starting with # or spaces are skiped except in strings or in [Generate]
+# Be carefull with [ it delimits sections!
+#
+
+[Configuration]
+#
+# No external program is needed!
+# @.html means: Copy the temporal file to xxxxx.html
+#
+CommandLine=@.html
+Name="Direct HTML 3.X format"
+
+[Delimiters]
+# Up to 11 characters
+SectionStart=/**[txh]**
+# Up to 11 characters
+SectionEnd=*********/
+
+[Variables]
+#
+# Up to 16 definitions
+#
+# Codes for the behavior of the definitions:
+# 1 Normal, put the content if found.
+# 2 Repeat, use the last value found in the file, ~no is an exeption, ~clear stops
+# 3 If not found replace by the prototype.
+# 4 If not found replace by the class.
+# 5 If not found replace by the name of the function
+# 6 It disables the node generation for this comment. The variable is
+# stored in the first variable that have associations and is in the comment.
+#
+# Additionally there are 2 special variables:
+# 90 Name of the file
+# 91 Line number of the end of the comment
+# 92 Name of the var 0 in the format: ~0 ~~Distinguish{(~Distinguish)~} (node name)
+#
+# 0 The first variable is the main index variable
+#
+AddDefinition=Function,5
+# 1
+AddDefinition=Class,4
+# 2
+AddDefinition=Include,2
+# 3
+AddDefinition=Module,2
+# 4
+AddDefinition=Prototype,3
+# 5
+AddDefinition=Description,1
+# 6
+AddDefinition=Return,1
+# 7
+AddDefinition=Example,1
+# 8
+AddDefinition=Comments,6
+#
+# It says what variable is added to distinguish between 2 vars 0 that are equal
+#
+Distinguish=1
+
+[Associations]
+#
+# Up to 8 associations
+#
+# The associations are between the 0 variable and another variable.
+#
+# Name in main menu, node, variable, optional to add to each node
+#
+#AddAssoc=List by modules,Modules,3
+AddAssoc=List by files,Files,90
+
+[Replace]
+#
+# All must be delimited by ", they can be used in the GenMain section
+#
+# Title of the HTML
+Constant="FreeBE/AF driver for TGUI9440AGi"
+
+# Description for the help
+Constant="This document describes the functions implemented in the
+TGUI9440AGi's FreeBE/AF driver.
+@p
+This document applies to version 1.0 of the driver.
+@p"
+
+[Commands]
+#
+# You can enclose these values between " to make more clear where
+# they start and end. Use \n,\r,\t and \" like in C. Use \ at the
+# end to concatenate like in C.
+#
+# @p = end of paragraph
+#
+EndOfPar=""
+#
+# @* = break line
+#
+BreakLine="
"
+#
+# @{value} is the special cross ref.
+# ~0 Is the visible name of a reference
+# ~1 Is the real name of a reference
+#
+CrossRef="~0"
+#
+# What we must get from a @@ sequence
+#
+Double@="@"
+
+[DefinedCommands]
+#
+# The format is @{parameters ...}
+#
+subtitle="~0"
+pre=
+/pre=
+
+#
+# This section says how to translate ASCIIs
+#
+[ASCIIConvert]
+ =á
+‚=é
+¡=í
+¢=ó
+£=ú
+¤=ñ
+¥=Ñ
+=¡
+¨=¿
+„=ä
+‰=ë
+‹=ï
+”=ö
+=ü
+š=Ü
+…=à
+Š=è
+=ì
+•=ò
+—=ù
+<=<
+>=>
+
+#
+# Use ~number to use one variable
+# Use ~~number{} for conditional, all the code inside {} will become
+# conditional
+# This section isn't passed for the macro expansion so here you are
+# free to use special commands for the formater.
+#
+[GenNode]
+
+
+~0 (~90 ~91)
+
+Syntax
+
+~~2{
+
+# This line is a comment, but the next is code
+ #include <~2>
+
+~}
+~~4{
+
+ ~4;
+
+~}
+~~1{
+Member of the class:
+~1
+
+~}
+
+~~5{
+Description
+
+~5
+
+~}
+~~6{
+Return Value
+
+~6
+
+~}
+~~7{
+Example
+
+~7
+
+~}
+
+[GenMenu]
+Start="
"
+
+#
+# ~1 is the name of the association
+# ~2 is the menu for it
+#
+[GenAssoMain]
+
+
+~1
+
+~2
+#
+# ~1 is the name of the association
+# ~2 is the name without the distinguish
+# ~3 is the comment for it
+# ~4 is the menu for it
+#
+[GenAssoRest]
+
+
+~2
+
+~3
+
+~4
+
+#
+# ~1 Main menu
+# ~2 Name of the function list node
+# ~3 Menu for all the functions
+# ~4 All the associations code
+# ~5 All the function nodes
+# ~50+ Values from section Replace
+#
+[GenMain]
+
+
+~50
+
+
+~50
+
+~51
+
+~1
+
+
+
+~2
+
+~3
+
+~4
+
+~5
+
+
+
diff --git a/tgui/mytypes.h b/tgui/mytypes.h
new file mode 100644
index 0000000..452a280
--- /dev/null
+++ b/tgui/mytypes.h
@@ -0,0 +1,5 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+typedef unsigned char uchar;
+typedef unsigned short ushort;
diff --git a/tgui/notes.txt b/tgui/notes.txt
new file mode 100644
index 0000000..bcbcf6d
--- /dev/null
+++ b/tgui/notes.txt
@@ -0,0 +1,165 @@
+
+ ______ ____ ______ _____ ______
+ | ____| | _ \| ____| / / _ \| ____|
+ | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ | | | | | __/ __/ |_) | |____ / / | | | | |
+ |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+
+
+ Trident TGUI9440AGi driver implementation notes.
+
+ Warning: My english is bad ;-)
+
+
+ This is the FreeBE/AF implementation for the Trident 9440 chipset for
+ PCI boards.
+ The driver is quite complet but there are some limitations:
+
+ 1) The driver doesn't work under Windows.
+ 2) The driver doesn't work with SciTech tools like vbetest.exe.
+ 3) The hardware cursor isn't 100% compliant.
+
+ Here are explanations about each topic:
+
+ 1) Trident drivers for Windows aren't good wenough to support a DOS
+ application setting the mode at register level. The drivers can emulate
+ VBE calls successfully but virtualize some critical registers avoiding
+ changes to this registers.
+ I think that isn't an important limitation because the main goal of
+ this driver is enhance the performance of DOS Allegro programs and they
+ works much better under pure DOS.
+
+ 2) I realised it too late, but this time SciTech taked the desition to
+ close the Nucleus standard (the VBE/AF sucesor). So I'll address this
+ topic only if somebody really needs support for it.
+
+ 3) In the future I'll add a way to disable the hardware cursor
+ acceleration, but by now I think is better to let it on all the time.
+
+ The implemented routines are the following:
+
+ WaitTillIdle()
+ SetMix()
+ Set8x8MonoPattern()
+ Set8x8ColorPattern()
+ Use8x8ColorPattern()
+ DrawScan()
+ DrawScanList()
+ DrawPattScan()
+ DrawPattScanList()
+ DrawColorPattScan()
+ DrawColorPattScanList()
+ DrawRect()
+ DrawPattRect()
+ DrawColorPattRect()
+ DrawLine()
+ DrawTrap() *4
+ SetLineStipple() *1
+ SetLineStippleCount() *1
+ DrawStippleLine() *1
+ PutMonoImage()
+ BitBlt()
+ BitBltSys()
+ SrcTransBlt()
+ SrcTransBltSys()
+ GetVideoModeInfo()
+ SetVideoMode() *3
+ RestoreTextMode()
+ SetDisplayStart()
+ SetActiveBuffer()
+ SetVisibleBuffer()
+ GetDisplayStartStatus() *5
+ SetBank()
+ SetPaletteData()
+ SetCursor()
+ SetCursorPos()
+ SetCursorColor() *2
+ ShowCursor()
+ GetClosestPixelClock()
+
+ Notes:
+ *1 I'm not sure about the implementation but the functions have
+ equivalent registers in the chip.
+ *2 9440 doesn't support it, that's a wrapper.
+ *3 Supports the AF_CRTCInfo parameter!
+ *4 Implemented using scans because isn't supported by the hard.
+ *5 Dummy because looks like TGUI doesn't set the interrupt flag.
+
+ Additionally I did some attempts to implement the following Inertia
+ functions, but they are disabled because SciTech dropped it:
+
+ GetConfigInfo
+ GetCurrentMode
+ SetVSyncWidth
+ GetVSyncWidth
+ GetBank
+ GetVisibleBuffer
+ GetDisplayStart
+ SetDisplayStartAddr
+ IsVSync
+ WaitVSync
+ GetActiveBuffer
+ IsIdle
+
+ The driver was implemented without using BIOS calls for this reason is
+ much more complex than current FreeBE/AF drivers (october 1998).
+ TGUI9440 doesn't support acelerations in 24 bpp, the modes are supported
+ but without accelerations.
+
+ Supported video modes:
+
+ 8 bpp 15 bpp 16 bpp 24 bpp
+ 320x200 * * * *
+ 320x240 * * * *
+ 400x300 * * * *
+ 512x384 * * * *
+ 576x432 * * * *
+ 640x400 * * * *
+ 640x480 * * * *
+ 720x540 * * * *
+ 800x600 * * * *
+ 900x675 * * * *
+ 1024x768 * * * (1)
+
+ (1) Needs more than 2Mb so is impossible with 9440
+
+ Other modes could be implemented using AF_CRTCInfo and
+ GetClosestPixelClock, that's a good feature of VBE/AF.
+
+
+ Technical notes:
+ * I'm bliting to the 0xA0000 region instead of the LFB in BitBltSys
+ because that's faster in the Ivan's motherboard, don't ask me why.
+ * See the sources for more information.
+ * Addtionally you can take a look to the vbeaf.htm included, it was
+ generated by my editor with almost no extra efforts.
+
+
+ Thanks to:
+ * The rest of the FreeBE/AF team, specially Shawn, the stub helped a lot
+ and I took ideas from various drivers.
+ * The people at Trident, they sent me the printed manuals of the board
+ without asking a cent (they invested money on it!)
+ * Kendall Benett, even when SciTech taked the desition to close the
+ Nucleus spec Kendall was very kind answering some questions about
+ functions, specially about the AF_CRTCInfo structure.
+ * Ivan Baldo, my beta tester.
+
+
+ Legal notes:
+ * All trademarks are property of their owners ;-))), I don't know why
+ manuals point out it, sounds funny no?
+ * The fonts included where dumped from the Trident's BIOS, I guess that's
+ OK because the driver works only with Trident boards ;-).
+ * Here goes another silly one: The information presented in this
+ publication has been carefully tested for reliability; however, no
+ responsability is assumed for inaccuracies. Specifications are subject
+ to change without notice. =-))))))))))
+ * Now seriously: this driver is under the FreeBE/AF license and no
+ warranty is provided (after all: try to sue M$ for the time lost
+ reinstalling Windows over and over each time it screws your HD ;-).
+
+
+ By Salvador Eduardo Tropea (SET)
+ set-soft@usa.net
diff --git a/tgui/regs.h b/tgui/regs.h
new file mode 100644
index 0000000..f10601f
--- /dev/null
+++ b/tgui/regs.h
@@ -0,0 +1,144 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+
+/*
+ List of ports used:
+ 0x3C0,0x3C1,0x3C2,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CC,0x3CE,
+ 0x3CF,0x3D4,0x3D5,0x3DA
+ TGUI:
+ 0x3D8,0x3D9,0x3DB,0x43C6,0x43C7,0x43C8,0x43C9,0x83C6,0x83C8
+ 0x2100-0x21FF
+*/
+/* CRT (Cathode Rays Tube) Controller Registers
+ They control the sync signals.
+ 0x00 to 0x18 */
+// SVGALib and XFree86 uses <0x18 so they miss the line compare register,
+// don't know why.
+#define CRTbase 0
+#define CRTcant 25
+/* ATT Attribute Controller Registers
+ They control some attributes like 16 colors palette, overscan color, etc.
+ 0x00 to 0x14 */
+#define ATTbase (CRTbase+CRTcant)
+#define ATTcant 21
+/* GRA Graphics Controller Registers
+ They control the read/write mode to the video memory.
+ 0x00 to 0x08 */
+#define GRAbase (ATTbase+ATTcant)
+#define GRAcant 9
+/* SEQ Sequence Registers
+ They control how the memory is scanned.
+ 0x00 to 0x04 */
+#define SEQbase (GRAbase+GRAcant)
+#define SEQcant 5
+/* MOR Miscellaneous Output Register
+ 1 register */
+#define MORbase (SEQbase+SEQcant)
+#define MORcant 1
+
+#define VGARegsCant (MORbase+MORcant)
+
+/* Status values: Here I store special status values that doesn't
+ correspond to a physical register but to an operation plus some
+ special registers */
+#define SPbase 0
+#define SPcant 12
+#define OldNewStatus SPbase+0
+#define ALT_BNK_WRITE SPbase+1
+#define ALT_BNK_READ SPbase+2
+#define ALT_CLK SPbase+3
+#define DAC_3C6 SPbase+4
+#define DAC_3C6_4th SPbase+5
+#define DAC_WR_ADD SPbase+6
+#define MCLKLOW SPbase+7
+#define MCLKHIG SPbase+8
+#define VCLKLOW SPbase+9
+#define VCLKHIG SPbase+10
+#define DAC_INDEX SPbase+11
+/* ESEQ Extra Sequence Registers
+ 0x08 to 0x0F (They have some tricks) */
+#define ESEQbase (SPbase+SPcant)
+#define ESEQcant 5
+#define ESEQ_0D_old ESEQbase+0
+#define ESEQ_0E_old ESEQbase+1
+#define ESEQ_0D_new ESEQbase+2
+#define ESEQ_0E_new ESEQbase+3
+#define ESEQ_0F ESEQbase+4
+/* ECRT Extra CRT Registers
+ 0x19 to 0x50 */
+#define ECRTbase (ESEQbase+ESEQcant)
+#define ECRTcant 33
+#define ECRT_19 ECRTbase
+#define ECRT_1E ECRTbase+1
+#define ECRT_1F ECRTbase+2
+#define ECRT_20 ECRTbase+3
+#define ECRT_21 ECRTbase+4
+#define ECRT_22 ECRTbase+5
+#define ECRT_23 ECRTbase+6
+#define ECRT_24 ECRTbase+7
+#define ECRT_25 ECRTbase+8
+#define ECRT_26 ECRTbase+9
+#define ECRT_27 ECRTbase+10
+#define ECRT_28 ECRTbase+11
+#define ECRT_29 ECRTbase+12
+#define ECRT_2A ECRTbase+13
+#define ECRT_2C ECRTbase+14
+#define ECRT_2F ECRTbase+15
+#define ECRT_30 ECRTbase+16
+#define ECRT_33 ECRTbase+17
+#define ECRT_34 ECRTbase+18
+#define ECRT_35 ECRTbase+19
+#define ECRT_36 ECRTbase+20
+#define ECRT_37 ECRTbase+21
+#define ECRT_38 ECRTbase+22
+#define ECRT_39 ECRTbase+23
+#define ECRT_40 ECRTbase+24
+#define ECRT_41 ECRTbase+25
+#define ECRT_42 ECRTbase+26
+#define ECRT_43 ECRTbase+27
+#define ECRT_44 ECRTbase+28
+#define ECRT_45 ECRTbase+29
+#define ECRT_46 ECRTbase+30
+#define ECRT_47 ECRTbase+31
+#define ECRT_50 ECRTbase+32
+/* EGRA Extra Graphics Controller Registers
+ 0x0E, 0x0F, 0x23 and 0x2F */
+#define EGRAbase (ECRTbase+ECRTcant)
+#define EGRAcant 4
+#define EGRA_0E_old EGRAbase
+#define EGRA_0F EGRAbase+1
+#define EGRA_23 EGRAbase+2
+#define EGRA_2F EGRAbase+3
+/* EDAC Extra DAC/Clk */
+#define EDACbase (EGRAbase+EGRAcant)
+#define EDACcant 4
+#define EDAC_00 EDACbase+0
+#define EDAC_01 EDACbase+1
+#define EDAC_02 EDACbase+2
+#define EDAC_03 EDACbase+3
+/* GER Graphics Engine Register. Only the relevant stuff */
+/* 0x22 and 0x23 */
+#define GERbase (EDACbase+EDACcant)
+#define GERcant 6
+#define GER_22 GERbase+0
+#define GER_23 GERbase+1
+#define GER_44 GERbase+2
+#define GER_45 GERbase+3
+#define GER_46 GERbase+4
+#define GER_47 GERbase+5
+
+#define SVGARegsCant (GERbase+GERcant)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int VGASaveRegs(uchar *regs, uchar *Sregs);
+void VGALoadRegs(const uchar *regs,const uchar *Sregs);
+void TGUI9440SaveRegs(uchar *regs);
+void TGUI9440LoadRegs(const uchar *regs);
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/tgui/rw_regs.c b/tgui/rw_regs.c
new file mode 100644
index 0000000..4f66673
--- /dev/null
+++ b/tgui/rw_regs.c
@@ -0,0 +1,463 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/*****************************************************************************
+
+ ROUTINES to store/retrieve the VGA and TGUI registers.
+
+*****************************************************************************/
+
+#include
+#include "mytypes.h"
+#include "regs.h"
+#include "vga.h"
+#include "tgui.h"
+
+//#include
+
+/**[txh]********************************************************************
+
+ Description:
+ This routines captures the TGUI registers in an array. Not all are stored
+because isn't needed by now. In fact I'm storing a lot of registers that
+are not needed to store.
+
+***************************************************************************/
+
+void TGUI9440SaveRegs(uchar *regs)
+{
+ int Old_New;
+ int i,Protect,DACaccess,DACaddress;
+
+ /* Extended Sequencer */
+ /* 8 is an status (old/new mode, field under scaning, FIFO in use) */
+ Old_New=ReadSEQ(8);
+ regs[OldNewStatus]=Old_New;
+ /* 9 is the revision code, A reserved, B chip ID */
+ /* Enter in old mode */
+ WriteSEQ(0xB,0);
+ regs[ESEQ_0D_old]=ReadSEQ(0xD);
+ regs[ESEQ_0E_old]=ReadSEQ(0xE);
+ regs[EGRA_0E_old]=ReadGRA(0xE);
+ /* Enter in new mode */
+ ReadSEQ(0xB);
+ regs[ESEQ_0D_new]=ReadSEQ(0xD);
+ //fprintf(stderr,"Lectura: %X %X\n",ReadSEQ(0x8),ReadSEQ(0xD));
+ Protect=
+ regs[ESEQ_0E_new]=ReadSEQ(0xE);
+ regs[ESEQ_0F] =ReadSEQ(0xF);
+ /* Unprotect the registers */
+ WriteSEQ(0xE,Protect | 0x80);
+
+ DACaccess=
+ regs[EGRA_0F]=ReadGRA(0xF);
+ regs[EGRA_23]=ReadGRA(0x23);
+ regs[EGRA_2F]=ReadGRA(0x2F);
+ /* Enable access to the DAC */
+ WriteGRA(0xF,DACaccess | 4);
+
+ /* These are alternative registers so I don't know if I really need to
+ store your content */
+ regs[ALT_BNK_WRITE]=inportb(0x3D8);
+ regs[ALT_BNK_READ] =inportb(0x3D9);
+ regs[ALT_CLK] =inportb(0x3DB);
+
+
+ /* These extended register are located in the CRT space but they aren't
+ contiguous */
+ regs[ECRTbase]=ReadCRT(0x19); // 0 (0x19)
+ for (i=1; i<14; i++)
+ regs[ECRTbase+i]=ReadCRT(0x1D+i); // 1-13 (0x1D-0x2A)
+ regs[ECRTbase+i]=ReadCRT(0x2C); // 14
+ i++;
+ regs[ECRTbase+i]=ReadCRT(0x2F); // 15
+ i++;
+ regs[ECRTbase+i]=ReadCRT(0x30); // 16
+ for (i++; i<24; i++)
+ regs[ECRTbase+i]=ReadCRT(0x22+i); // 17-23
+ for (; i<32; i++)
+ regs[ECRTbase+i]=ReadCRT(0x28+i); // 24-31
+ regs[ECRTbase+i]=ReadCRT(0x50); // 32
+
+ /* Map the DAC safetly (0x3C6 so doesn't overlap others) */
+ DACaddress=ReadCRT(0x29);
+ WriteCRT(0x29,DACaddress & 0xFC);
+ regs[DAC_3C6] =inportb(0x3C6);
+ inportb(0x3C6); inportb(0x3C6); inportb(0x3C6);
+ regs[DAC_3C6_4th]=inportb(0x3C6);
+ regs[DAC_WR_ADD] =inportb(0x3C8);
+ regs[MCLKLOW] =inportb(0x43C6);
+ regs[MCLKHIG] =inportb(0x43C7);
+ regs[VCLKLOW] =inportb(0x43C8);
+ regs[VCLKHIG] =inportb(0x43C9);
+ regs[DAC_INDEX] =inportb(0x83C8);
+
+ for (i=0; i>6); /* b8 */
+ a|=((start & 0x200)>>2); /* b9 */
+ WriteCRT(0x7,a);
+ a=ReadCRT(0x27) & 0xBF;
+ a|=((start & 0x400)>>4); /* b10 */
+ WriteCRT(0x27,a);
+ WriteCRT(0x11,0x80 | (end & 0x0F));
+}
+#endif
+
+/*
+* means stored
+
+ 3C3 [No] (Hardware specific)
+ 46E8 [No] (Hardware specific)
+*3C5.08 We must save b7 to recreate the old/new mode and manipulate it.
+ 3C5.09 [No!] (RO)
+ 3C5.0A [No] (Reserved)
+ 3C5.0B [No!] (RO)
+ 3C5.0C-1 [No] (Hardware specific)
+ 3C5.0C-2 [No] (BIOS reserved)
+*3C5.0D-old [No] CB (Hardware specific)
+*3C5.0E-old
+*3CF.0E-old
+*3C5.0D-new
+*3C5.0E-new We must manipulate b7 for other registers (enable from here and
+ restart at the end).
+ 3CF.0E-new [No!] Have alternative and could mess the alternative.
+*3C5.0F [No] (Hardware specific)
+*3CF.0F We must enable b2 and restart at the end.
+*3CF.23
+*3CF.2F
+*3D8
+*3D9
+*3DB
+*3D5.19
+*3D5.1E
+*3D5.1F [No] CB (Reserved) BIOS stores the amount of memory here and the driver
+ will read it just once so we don't need to save it.
+*3D5.20
+*3D5.21 [No] CB It contols the Linear Address but I can't understand how it
+ works.
+*3D5.22
+*3D5.23 [No] CB It fine tunes the DRAM speed.
+*3D5.24
+*3D5.25
+*3D5.26
+*3D5.27
+*3D5.28 [No] (Hardware specific)
+*3D5.29 we must clear b0-1 and enable at the end to access the DAC.
+*3D5.2A [No] (Hardware specific)
+*3D5.2C
+*3D5.2F
+*3D5.30 [No] (Reserved)
+*3D5.33
+*3D5.34
+*3D5.35
+*3D5.36
+*3D5.37 [No] (Hardware specific)
+*3D5.38
+*3D5.39 [No] (Hardware specific)
+*3D5.40-47,50 Ok Hardware cursor.
+
+*3C6
+ Here comes a crazy thing: we read 3 times more 3C6
+*3C6 (This time is a different value).
+
+ 3C7 [No!] the read back value isn't usefull
+*3C8 Ok the read back is the address.
+ 3C9 [No!] we save the whole palette ;-)
+
+*43C6-9
+*83C8 That's the 83C6/8 index.
+*83C6.00
+*83C6.01
+*83C6.02
+*83C6.03
+*83C6.04
+ 83C6.05 [No!] (RO)
+ 83C6.30 [No] The following are very optional:
+ 83C6.31 [No]
+ 83C6.32 [No]
+ 83C6.34 [No]
+ 83C6.35 [No]
+ 83C6.36 [No]
+ 83C6.37 [No]
+ 83C6.38 [No]
+*GER.22
+*GER.23 22-23 sets the pitch and offset of the operations
+*GER.44-47 (patterned lines parameters)
+The rest of the GER can change in any way because I set all the values from
+call to call.
+*/
+
+
diff --git a/tgui/setmode.c b/tgui/setmode.c
new file mode 100644
index 0000000..55d2f5e
--- /dev/null
+++ b/tgui/setmode.c
@@ -0,0 +1,1040 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/*****************************************************************************
+
+ ROUTINES to modify the VGA and TGUI registers to set a video mode
+
+*****************************************************************************/
+
+#include
+#include "mytypes.h"
+#include "regs.h"
+#include "vga.h"
+#include "setmode.h"
+#include "tgui.h"
+
+#include "font.h"
+
+/*
+ This structure holds all VGA the registers captured from 320x200x8bpp. Some
+of them where cleared for better defaults or when setting some bits.
+*/
+uchar DefaultVGARegs[VGARegsCant]={
+/* CRT Controller Registers */
+0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, /* 0 - 7 */
+0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 - F */
+0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3, /* 10 - 17 */
+0xFF,
+/* Attribute Controller Registers */
+0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+0x41, 0x00, 0x0F, 0x00, 0x00,
+/* Graphics Controller Registers */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+0xFF,
+/* Sequence Registers */
+0x03, 0x01, 0x0F, 0x00, 0x0E,
+/* Miscellaneous Output Register */
+0x23
+};
+
+/* VGA Text mode 80x25 (mode 3) */
+uchar TextModeVGARegs[VGARegsCant]={
+/* CRT Controller Registers */
+0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
+0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00,
+0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
+0xFF,
+/* Attribute Controller Registers */
+0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+0x0C, 0x00, 0x0F, 0x08, 0x00,
+/* Graphics Controller Registers */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
+0xFF,
+/* Sequence Registers */
+0x03, 0x00, 0x03, 0x00, 0x02,
+/* Miscellaneous Output Register */
+0x67
+};
+
+uchar TextModeFont[256*16];
+
+/* The working copies are used to create a video mode */
+uchar WorkingVGARegs[VGARegsCant];
+uchar WorkingSVGARegs[SVGARegsCant];
+/* That's the state of the TGUI at start. I must use it because some bits
+ controls harware specific things so I can't use a set of values taked
+ from my board */
+uchar CapturedSVGARegs[SVGARegsCant];
+
+/*
+ I created 320x240, 400x300, 512x384, 576x432, 720x540 and 900x675
+
+ Notes:
+ * Changing CRT4 you can center horizontally.
+ * Changing Vtotal you can reduce the vertical size.
+
+*/
+
+VideoModeStr g320x200x8=
+{
+ NHSync | PVSync | BPP8 | DoubleScan | HaveAccel2D,
+ 320,336,376,400,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 512,
+ /* Clock: Programmed to 25.175/2 MHz fh=31.47 KHz fv=70.09 Hz OK! +V -H */
+ 0 | VClockDiv2,0x19,0xC2
+ //2 | VClockDiv2,0x1E,0xE5 12.586142 MHz fh=31.47 KHz fv=70.08 Hz
+};
+
+VideoModeStr g320x200x15=
+{
+ NHSync | PVSync | BPP15 | DoubleScan | HaveAccel2D,
+ 320,336,376,400,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.18 MHz fh=31.475 KHz fv=70.1 Hz OK! +V -H */
+ 0,0x19,0xC2
+};
+
+VideoModeStr g320x200x16=
+{
+ NHSync | PVSync | BPP16 | DoubleScan | HaveAccel2D,
+ 320,336,376,400,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.18 MHz fh=31.475 KHz fv=70.1 Hz OK! +V -H */
+ 0,0x19,0xC2
+};
+
+VideoModeStr g320x200x24=
+{
+ NHSync | PVSync | BPP24 | DoubleScan,
+ 320,336,376,400,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 960,
+ /* Clock: Programmed to 37.75 MHz fh=31.46 KHz fv=70.1 Hz OK! +V -H */
+ 2,0x14,0xB2
+};
+
+VideoModeStr g320x240x8=
+{
+ NHSync | NVSync | BPP8 | DoubleScan | HaveAccel2D,
+ 320,336,384,408,
+ 480,490,508,527,
+ /* minimal bytes per scan needed for this mode */
+ 512,
+ /* Clock: Programmed to 25.65/2 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
+ /* That's almost IBM's VGA3/60Hz mode */
+ 2 | VClockDiv2,0x15,0x23
+};
+
+VideoModeStr g320x240x15=
+{
+ NHSync | NVSync | BPP15 | DoubleScan | HaveAccel2D,
+ 320,336,384,408,
+ 480,490,508,527,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.65 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
+ /* That's almost IBM's VGA3/60Hz mode */
+ 2,0x15,0x23
+};
+
+VideoModeStr g320x240x16=
+{
+ NHSync | NVSync | BPP16 | DoubleScan | HaveAccel2D,
+ 320,336,384,408,
+ 480,490,508,527,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.65 MHz fh=31.43 KHz fv=59.7 Hz OK! -V -H */
+ /* That's almost IBM's VGA3/60Hz mode */
+ 2,0x15,0x23
+};
+
+VideoModeStr g320x240x24=
+{
+ NHSync | NVSync | BPP24 | DoubleScan,
+ 320,344,384,424,
+ 480,490,492,525,
+ /* minimal bytes per scan needed for this mode */
+ 960,
+ /* Clock: Programmed to 40.09 MHz fh=31.52 KHz fv=60.15 Hz OK! -V -H */
+ /* That's almost IBM's VGA3/60Hz mode */
+ 2,0x14,0x30
+};
+
+VideoModeStr g400x300x8=
+{
+ PHSync | PVSync | BPP8 | DoubleScan | HaveAccel2D,
+ 400,428,492,528,
+ 600,601,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 512,
+ /* Clock: Programmed to 37.14/2 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
+ /* These are the syncs for 800/56Hz VESA standard mode */
+ 2 | VClockDiv2,0x17,0x4B
+};
+
+VideoModeStr g400x300x15=
+{
+ PHSync | PVSync | BPP15 | DoubleScan | HaveAccel2D,
+ 400,428,492,528,
+ 600,601,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 800,
+ /* Clock: Programmed to 37.14 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
+ /* These are the syncs for 800/56Hz VESA standard mode */
+ 2,0x17,0x4B
+};
+
+VideoModeStr g400x300x16=
+{
+ PHSync | PVSync | BPP16 | DoubleScan | HaveAccel2D,
+ 400,428,492,528,
+ 600,601,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 800,
+ /* Clock: Programmed to 37.14 MHz fh=35.17 KHz fv=56 Hz OK! +V +H */
+ /* These are the syncs for 800/56Hz VESA standard mode */
+ 2,0x17,0x4B
+};
+
+VideoModeStr g400x300x24=
+{
+ PHSync | PVSync | BPP24 | DoubleScan,
+ 400,428,492,528,
+ 600,601,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 1200,
+ /* Clock: Programmed to 55.74 MHz fh=35.19 KHz ~fv=56 Hz OK! +V +H */
+ /* These are the syncs for 800/56Hz VESA standard mode */
+ 2,0x16,0x65
+};
+
+VideoModeStr g512x384x8=
+{
+ NHSync | PVSync | BPP8 | HaveAccel2D,
+ 512,528,576,640,
+ 384,400,414,442,
+ /* minimal bytes per scan needed for this mode */
+ 512,
+ /* Clock: Programmed to 39.97/2 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
+ /* Very close to IBM's VGA2/70 */
+ 2 | VClockDiv2,0x15,0x3B
+};
+/* Another option could be:
+"512x384" 20.401 512 536 560 648 384 404 406 449 -Hsync +Vsync
+ 31.483kHz/70.12Hz
+*/
+
+VideoModeStr g512x384x15=
+{
+ NHSync | PVSync | BPP15 | HaveAccel2D,
+ 512,528,576,640,
+ 384,400,414,442,
+ /* minimal bytes per scan needed for this mode */
+ 1024,
+ /* Clock: Programmed to 39.97 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
+ /* Very close to IBM's VGA2/70 */
+ 2,0x15,0x3B
+};
+
+VideoModeStr g512x384x16=
+{
+ NHSync | PVSync | BPP16 | HaveAccel2D,
+ 512,528,576,640,
+ 384,400,414,442,
+ /* minimal bytes per scan needed for this mode */
+ 1024,
+ /* Clock: Programmed to 39.97 MHz fh=31.23 KHz fv=70.6 Hz OK! +V -H */
+ /* Very close to IBM's VGA2/70 */
+ 2,0x15,0x3B
+};
+
+VideoModeStr g512x384x24=
+{
+ NHSync | PVSync | BPP24,
+ 512,528,576,640,
+ 384,400,414,442,
+ /* minimal bytes per scan needed for this mode */
+ 1024,
+ /* Clock: Programmed to 60.03 MHz fh=31.26 KHz fv=70.7 Hz OK! +V -H */
+ /* Very close to IBM's VGA2/70 */
+ 2,0x15,0xE5
+};
+
+VideoModeStr g576x432x8=
+{
+ //NHSync | PVSync | BPP8,
+ NHSync | NVSync | BPP8 | HaveAccel2D,
+ 576,604,692,720,
+ 432,442,444,473,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 45.34/2 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
+ /* That's a little messy standard verticals are 60 and 70 Hz */
+ 2 | VClockDiv2,0x10,0x8B
+};
+
+VideoModeStr g576x432x15=
+{
+ NHSync | NVSync | BPP15 | HaveAccel2D,
+ 576,604,692,720,
+ 432,442,444,473,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 45.34 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
+ /* That's a little messy standard verticals are 60 and 70 Hz */
+ 2,0x10,0x8B
+};
+
+VideoModeStr g576x432x16=
+{
+ NHSync | NVSync | BPP16 | HaveAccel2D,
+ 576,604,692,720,
+ 432,442,444,473,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 45.34 MHz fh=31.49 KHz fv=66.6 Hz OK! -V -H */
+ /* That's a little messy standard verticals are 60 and 70 Hz */
+ 2,0x10,0x8B
+};
+
+VideoModeStr g576x432x24=
+{
+ NHSync | NVSync | BPP24,
+ 576,604,692,720,
+ 432,442,444,473,
+ /* minimal bytes per scan needed for this mode */
+ 1728,
+ /* Clock: Programmed to 67.41 MHz fh=31.21 KHz fv=66 Hz OK! -V -H */
+ /* That's a little messy standard verticals are 60 and 70 Hz */
+ 2,0x15,0x69
+};
+
+#if 0
+VideoModeStr g512x384x8=
+{
+ NHSync | NVSync | BPP8 | HaveAccel2D,
+ 512,384,
+ /* minimal bytes per scan needed for this mode */
+ 512,
+ /* Horizontal CRT timing (CRT0-5) 640 */
+ 0x4B, 0x3F, 0x40, 0x8E, 0x42, 0x08,
+ /* Vertical CRT timing (CRT6,7,9,10,11,12,15,16) 409 */
+ 0x98, 0x1F, 0x00, 0x81, 0x86, 0x7F, 0x83, 0x95,
+ /* SVGA Overflows */
+ 0x00,
+ /* Clock: Programmed to 39.7 MHz fh=31 KHz fv=75 Hz */
+ 0x42,0x14,0xB5
+};
+#endif
+
+VideoModeStr g640x400x8=
+{
+ NHSync | PVSync | BPP8 | HaveAccel2D,
+ 640,664,768,800,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.18 MHz fh=31.48 KHz fv=70.1 Hz */
+ /* IBM's VGA2/70 */
+ 0,0x19,0xC2
+};
+
+VideoModeStr g640x400x15=
+{
+ NHSync | PVSync | BPP15 | HaveAccel2D,
+ 640,664,768,800,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 50.11 MHz fh=31.32 KHz fv=69.8 Hz */
+ /* IBM's VGA2/70 */
+ 2,0x01,0x06
+};
+
+VideoModeStr g640x400x16=
+{
+ NHSync | PVSync | BPP16 | HaveAccel2D,
+ 640,664,768,800,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 50.11 MHz fh=31.32 KHz fv=69.8 Hz */
+ /* IBM's VGA2/70 */
+ 2,0x01,0x06
+};
+
+VideoModeStr g640x400x24=
+{
+ NHSync | PVSync | BPP24,
+ 640,664,768,800,
+ 400,412,414,449,
+ /* minimal bytes per scan needed for this mode */
+ 1920,
+ /* Clock: Programmed to 75.50 MHz fh=31.46 KHz fv=70.1 Hz */
+ /* IBM's VGA2/70 */
+ 2,0x04,0xB2
+};
+
+VideoModeStr g640x480x8=
+{
+ NHSync | NVSync | BPP8 | HaveAccel2D,
+ 640,664,768,800,
+ 480,490,492,525,
+ /* minimal bytes per scan needed for this mode */
+ 640,
+ /* Clock: Programmed to 25.23 MHz fh=31.53 KHz fv=60 Hz */
+ /* IBM's VGA3/60 */
+ 0,0x19,0xC2
+};
+
+VideoModeStr g640x480x15=
+{
+ NHSync | NVSync | BPP15 | HaveAccel2D,
+ 640,664,768,800,
+ 480,490,492,525,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 50.56 MHz ~fh=31.54 KHz ~fv=60 Hz */
+ /* IBM's VGA3/60 */
+ 2,0x17,0x69
+};
+
+VideoModeStr g640x480x16=
+{
+ NHSync | NVSync | BPP16 | HaveAccel2D,
+ 640,664,768,800,
+ 480,490,492,525,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Clock: Programmed to 50.56 MHz ~fh=31.54 KHz ~fv=60 Hz */
+ /* IBM's VGA3/60 */
+ 2,0x17,0x69
+};
+
+VideoModeStr g640x480x24=
+{
+ NHSync | NVSync | BPP24,
+ 640,664,768,800,
+ 480,490,492,525,
+ /* minimal bytes per scan needed for this mode */
+ 1920,
+ /* Clock: Programmed to 75.89 MHz fh=31.62 KHz fv=60.23 Hz */
+ /* IBM's VGA3/60 */
+ 2,0x04,0x2D
+};
+
+VideoModeStr g720x540x8=
+{
+ NHSync | NVSync | BPP8 | HaveAccel2D,
+ 720,770,886,950,
+ 540,552,554,590,
+ /* minimal bytes per scan needed for this mode */
+ 800,
+ /* Clock: Programmed to 31.94 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
+ /* A little messy too, both standard but not from the same mode */
+ 2,0x15,0xB2 // 31.94
+};
+
+VideoModeStr g720x540x15=
+{
+ NHSync | NVSync | BPP15 | HaveAccel2D,
+ 720,770,886,950,
+ 540,552,554,590,
+ /* minimal bytes per scan needed for this mode */
+ 1600,
+ /* Clock: Programmed to 63.88 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
+ /* A little messy too, both standard but not from the same mode */
+ 2,0x05,0xB2 // 63.88
+};
+
+VideoModeStr g720x540x16=
+{
+ NHSync | NVSync | BPP16 | HaveAccel2D,
+ 720,770,886,950,
+ 540,552,554,590,
+ /* minimal bytes per scan needed for this mode */
+ 1600,
+ /* Clock: Programmed to 63.88 MHz fh=35.49 KHz fv=60.2 Hz OK! -V -H */
+ /* A little messy too, both standard but not from the same mode */
+ 2,0x05,0xB2 // 63.88
+};
+
+VideoModeStr g720x540x24=
+{
+ NHSync | NVSync | BPP24,
+ 720,770,886,950,
+ 540,552,554,590,
+ /* minimal bytes per scan needed for this mode */
+ 2160,
+ /* Clock: Programmed to 95.82 MHz fh=35.49 KHz fv=60.15 Hz OK! -V -H */
+ /* A little messy too, both standard but not from the same mode */
+ 2,0x05,0xCF // 95.82
+};
+
+VideoModeStr g800x600x8=
+{
+ NHSync | NVSync | BPP8 | HaveAccel2D,
+ 800,856,984,1056,
+ 600,600,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 800,
+ /* Clock: Programmed to 37.14 MHz => fh=35.17 KHz fv=56 Hz */
+ /* VESA 800/56Hz */
+ 2,0x17,0x4B
+};
+
+VideoModeStr g800x600x15=
+{
+ NHSync | NVSync | BPP15 | HaveAccel2D,
+ 800,856,984,1056,
+ 600,600,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 1600,
+ /* Clock: Programmed to 74.28 MHz => fh=35.17 KHz fv=56 Hz */
+ /* VESA 800/56Hz */
+ 2,0x07,0x4B
+};
+
+VideoModeStr g800x600x16=
+{
+ NHSync | NVSync | BPP16 | HaveAccel2D,
+ 800,856,984,1056,
+ 600,600,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 1600,
+ /* Clock: Programmed to 74.28 MHz => fh=35.17 KHz fv=56 Hz */
+ /* VESA 800/56Hz */
+ 2,0x07,0x4B
+};
+
+VideoModeStr g800x600x24=
+{
+ NHSync | NVSync | BPP24,
+ 800,856,984,1056,
+ 600,600,604,628,
+ /* minimal bytes per scan needed for this mode */
+ 2400,
+ /* Clock: Programmed to 111.48 MHz => fh=35.19 KHz fv=56.03 Hz */
+ /* VESA 800/56Hz */
+ 2,0x06,0x65
+};
+
+VideoModeStr g900x675x8=
+{
+ NHSync | PVSync | BPP8 | HaveAccel2D,
+ 900,904,1076,1110,
+ 675,675,680,719,
+ /* minimal bytes per scan needed for this mode */
+ 1024,
+ /* Clock: Programmed to 39.77 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
+ /* Really messy, 50 Hz isn't standard at all */
+ 2,0x13,0xAA
+};
+
+VideoModeStr g900x675x15=
+{
+ NHSync | PVSync | BPP15 | HaveAccel2D,
+ 900,904,1076,1110,
+ 675,675,680,719,
+ /* minimal bytes per scan needed for this mode */
+ 2048,
+ /* Clock: Programmed to 79.55 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
+ /* Really messy, 50 Hz isn't standard at all */
+ 2,0x03,0xAA
+};
+
+VideoModeStr g900x675x16=
+{
+ NHSync | PVSync | BPP16 | HaveAccel2D,
+ 900,904,1076,1110,
+ 675,675,680,719,
+ /* minimal bytes per scan needed for this mode */
+ 2048,
+ /* Clock: Programmed to 79.55 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
+ /* Really messy, 50 Hz isn't standard at all */
+ 2,0x03,0xAA
+};
+
+VideoModeStr g900x675x24=
+{
+ NHSync | PVSync | BPP24,
+ 900,904,1076,1110,
+ 675,675,680,719,
+ /* minimal bytes per scan needed for this mode */
+ 2700,
+ /* Clock: Programmed to 119.32 MHz fh=35.83 KHz fv=49.76 Hz OK! +V -H */
+ /* Really messy, 50 Hz isn't standard at all */
+ 2,0x00,0x91
+};
+
+VideoModeStr g1024x768x8=
+{
+ PHSync | PVSync | Interlaced | BPP8 | HaveAccel2D,
+ 1024,1040,1224,1264,
+ 384,385,390,410,
+ /* minimal bytes per scan needed for this mode */
+ 1024,
+ /* Clock: Programmed to 44.91 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
+ /* Standard XGA/87iHz */
+ 2,0x14,0xBD
+};
+
+VideoModeStr g1024x768x15=
+{
+ PHSync | PVSync | Interlaced | BPP15 | HaveAccel2D,
+ 1024,1040,1224,1264,
+ 384,385,390,410,
+ /* minimal bytes per scan needed for this mode */
+ 2048,
+ /* Clock: Programmed to 89.81 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
+ /* Standard XGA/87iHz */
+ 2,0x04,0xBD
+};
+
+VideoModeStr g1024x768x16=
+{
+ PHSync | PVSync | Interlaced | BPP16 | HaveAccel2D,
+ 1024,1040,1224,1264,
+ 384,385,390,410,
+ /* minimal bytes per scan needed for this mode */
+ 2048,
+ /* Clock: Programmed to 89.81 MHz => fh=35.53 KHz fv=43.43 Hz (*2) */
+ /* Standard XGA/87iHz */
+ 2,0x04,0xBD
+};
+
+#if 0
+VideoModeStr g1152x900x8=
+{
+ PHSync | PVSync | Interlaced | BPP8 | HaveAccel2D,
+ 1152,900,
+ /* minimal bytes per scan needed for this mode */
+ 1280,
+ /* Horizontal CRT timing (CRT0-5) ~1152 1424 */
+ 0xAD,0x8F,0x90,0x8F,0x93,0x8C,
+ /* Vertical CRT timing (CRT6,7,9,10,11,12,15,16) 450 458 */
+ 0xD3,0x1F,0x40,0xC2,0x87,0xC1,0xC2,0xD3, // Ok
+ //0xC8,0x1F,0x40,0xC2,0x87,0xC1,0xC2,0xC8,
+ /* SVGA Overflows CRT27 */
+ 0x00,
+ /* Clock: Programmed to 44.91 MHz => fh=35.50 KHz fv=77.5i Hz */
+ /* A real mess, better let it outside the list */
+ 2,0x17,0x69 // 50.56
+ //2,0x14,0xCB // 54.02
+};
+#endif
+
+VideoModeStr *SupportedVideoModes[]={
+ &g320x200x8, &g320x240x8, &g400x300x8, &g512x384x8, &g576x432x8, &g640x400x8,
+ &g640x480x8, &g720x540x8, &g800x600x8, &g900x675x8,&g1024x768x8,
+&g320x200x15,&g320x240x15,&g400x300x15,&g512x384x15,&g576x432x15,&g640x400x15,
+&g640x480x15,&g720x540x15,&g800x600x15,&g900x675x15,&g1024x768x15,
+&g320x200x16,&g320x240x16,&g400x300x16,&g512x384x16,&g576x432x16,&g640x400x16,
+&g640x480x16,&g720x540x16,&g800x600x16,&g900x675x16,&g1024x768x16,
+&g320x200x24,&g320x240x24,&g400x300x24,&g512x384x24,&g576x432x24,&g640x400x24,
+&g640x480x24,&g720x540x24,&g800x600x24,&g900x675x24
+};
+
+short SupportedVideoModesNums[]={
+ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, /* 8 bpp */
+12,13,14,15,16,17,18,19,20,21,22, /* 15 bpp */
+23,24,25,26,27,28,29,30,31,32,33, /* 16 bpp */
+34,35,36,37,38,39,40,41,42,43, /* 24 bpp */
+-1
+};
+
+int NumSupportedVideoModes=sizeof(SupportedVideoModes)/sizeof(VideoModeStr *);
+
+static int GERCanBeUsed;
+static int Pitchs[]={/*320,400,*/512,640,800,1024,1280,1600,2048,2560,3200,4096,-1};
+static uchar GER23v[]={/*1,3,*/0,1,3,0,1,3,0,1,3,0};
+static uchar GER22v[]={/*0,0,*/0,4,4,4,8,8,8,12,12,12};
+
+int GetBestPitchFor(int Width, int BytesPerPixel)
+{
+ int i;
+ int BytesPerScan=Width*BytesPerPixel;
+
+ if (BytesPerPixel==3)
+ { /* 24 bpp modes aren't supported by the accelerator */
+ if (Width>1360)
+ return -1;
+ /* Round to the next multiple of 8 */
+ if (BytesPerScan & 7)
+ BytesPerScan+=8-(BytesPerScan & 7);
+ return BytesPerScan;
+ }
+ /* Choose a supported pitch */
+ for (i=0; Pitchs[i]>0; i++)
+ {
+ if (Pitchs[i]>=BytesPerScan)
+ return Pitchs[i];
+ }
+ return -1;
+}
+
+/*
+ This function modifies the SVGA registers for the specified mode. Is called
+from the VGA counterpart.
+*/
+void SetForSVGAMode(VideoModeStr *mode,int VirtualWidth, uchar *r, uchar *rs,
+ unsigned vDisplay, unsigned vBlankStart, unsigned vSyncStart,
+ unsigned vTotal)
+{
+ //rs[ECRT_25]|=0x80;
+ /* b8 of Logical Width */
+ rs[ECRT_29]&=0xEC; /* b0-1 maps the DAC in the right place */
+ rs[ECRT_29]|=(((VirtualWidth/8) & 0x100)>>(8-4));
+ /* Clock */
+ rs[ALT_CLK]=mode->ClockType | 0xF;
+ rs[VCLKLOW]=mode->ClockValLow;
+ rs[VCLKHIG]=mode->ClockValHigh;
+ /* Copy the same values to the MOR */
+ r[MORbase]&=0xF3;
+ r[MORbase]|=(mode->ClockType & 0x3)<<2;
+ /* The original place for the divider NOT needed */
+ //rs[ESEQ_0D_new]&=0xF9;
+ //rs[ESEQ_0D_new]|=mode->ClockType>>5;
+ /* Enable bit 16 of Start Address */
+ /* Set No/Interlaced mode */
+ /* Protect Misc. Output Reg. */
+ rs[ECRT_1E]=0x80;
+ if (mode->flags & Interlaced)
+ rs[ECRT_1E]|=4;
+ /* Enable 32 bits internal Bus */
+ rs[ECRT_2A]|=0x40;
+ /* Enable alternative bank and clock */
+ /* Compressed chain 4 mode addressing */
+ rs[EGRA_0F]|=2 | 4;
+ /* Disable skew control */
+ rs[EGRA_2F]|=0x20;
+ if (mode->flags & Interlaced)
+ rs[EGRA_2F]|=4;
+ /* Set the pixel size */
+ GERCanBeUsed=1;
+ switch (ExtractBPP(mode->flags))
+ {
+ /* 8 bpp */
+ case 0:
+ rs[ECRT_38]&=0xF3; /* clear b2 and b3 */
+ rs[DAC_3C6_4th]=0; /* Pseudo color mode */
+ rs[EGRA_0F]&=0xB7; /* clear b3 and b6 */
+ rs[GER_22]=0;
+ break;
+ /* 15 bpp */
+ case 1:
+ rs[ECRT_38]&=0xF7; /* clear b3 */
+ rs[ECRT_38]|=4; /* set b2 */
+ rs[DAC_3C6_4th]=0x10; /* Hi Color mode */
+ rs[EGRA_0F]&=0xBF; /* clear b6 */
+ rs[EGRA_0F]|=8; /* set b3 */
+ rs[GER_22]=1;
+ break;
+ /* 16 bpp */
+ case 2:
+ rs[ECRT_38]&=0xF7; /* clear b3 */
+ rs[ECRT_38]|=4; /* set b2 */
+ rs[DAC_3C6_4th]=0x30; /* XGA mode */
+ rs[EGRA_0F]&=0xBF; /* clear b6 */
+ rs[EGRA_0F]|=8; /* set b3 */
+ rs[GER_22]=1;
+ break;
+ /* 24 bpp */
+ case 3:
+ rs[ECRT_38]&=0xFB; /* clear b2 */
+ rs[ECRT_38]|=8; /* set b3 */
+ rs[DAC_3C6_4th]=0xD0; /* True Color mode */
+ rs[EGRA_0F]&=0xF7; /* clear b3 */
+ rs[EGRA_0F]|=0x40; /* set b6 */
+ rs[GER_22]=2; /* Just for testing the effect */
+ GERCanBeUsed=0;
+ break;
+ }
+ /* SVGA overflows */
+ rs[ECRT_27]=0x8 | ((vDisplay & 0x400)>>6) |
+ ((vSyncStart & 0x400)>>5) |
+ ((vBlankStart & 0x400)>>4) |
+ ((vTotal & 0x400)>>3);
+
+ if (GERCanBeUsed)
+ { /* See if the width is compatible with the GER and what values to use */
+ int i=0;
+ while (Pitchs[i]>0)
+ {
+ if (Pitchs[i]==VirtualWidth)
+ {
+ rs[GER_23]=GER23v[i];
+ rs[GER_22]|=GER22v[i];
+ //break;
+ }
+ i++;
+ }
+ if (Pitchs[i]>0)
+ GERCanBeUsed=0;
+ }
+
+ /* Now set some initialization values */
+ /* Bank 0 for Write, we use 2 because bit 1 is inverted in the ESEQ_0E
+ I can't use the ALT_BNK_WRITE here because I write to ESEQ_0E at the
+ end of the loading so ESEQ_0E will overwrite ALT_BNK_WRITE.
+ Yes, is a complex issue. */
+ rs[ESEQ_0E_new]|=2;
+ /* Bank 0 for reading */
+ rs[ALT_BNK_READ]=0;
+ /* No mask any DAC bit, just in case */
+ rs[DAC_3C6]=0xFF;
+ /* Graphic Engine mapped in B7FXX and enabled */
+ rs[ECRT_36]=GERCanBeUsed ? 0x81 : 0;
+ rs[ECRT_21]=0xD6;
+}
+
+/*
+ This function modifies the VGA registers for the specified mode. Then calls
+to the SVGA counterpart.
+*/
+void SetForVGAMode(VideoModeStr *mode,int VirtualWidth,uchar *r, uchar *rs)
+{
+ unsigned Display,SyncStart,SyncEnd,Total,BlankEnd,BlankStart;
+
+ switch (ExtractBPP(mode->flags))
+ {
+ /* 8 bpp */
+ case 0:
+ break;
+ /* 15 bpp */
+ case 1:
+ VirtualWidth*=2;
+ break;
+ /* 16 bpp */
+ case 2:
+ VirtualWidth*=2;
+ break;
+ /* 24 bpp */
+ case 3:
+ VirtualWidth*=3;
+ break;
+ }
+ /* +/- H and V Sync */
+ r[MORbase]|=(mode->flags & 3)<<6;
+
+ /* Horizontal timing */
+ Display = mode->hDisplay/8;
+ SyncStart = mode->hSyncStart/8;
+ SyncEnd = mode->hSyncEnd/8;
+ Total = mode->hTotal/8;
+ BlankEnd = Total-2; /* Left 2 for borders */
+ BlankStart = Display;
+
+ r[CRTbase+0x00]=Total-5;
+ r[CRTbase+0x01]=Display-1;
+ r[CRTbase+0x02]=BlankStart; // Blank Start
+ r[CRTbase+0x03]=0x80 | (BlankEnd & 0x1F);
+ r[CRTbase+0x04]=SyncStart;
+ r[CRTbase+0x05]=(SyncEnd & 0x1F) | ((BlankEnd & 0x20)<<2);
+ /* Logical Width (Offset) */
+ r[CRTbase+0x13]=VirtualWidth/8;
+
+ /* Vertical timing */
+ Display = mode->vDisplay;
+ SyncStart = mode->vSyncStart;
+ SyncEnd = mode->vSyncEnd;
+ Total = mode->vTotal;
+ BlankEnd = Total-2; /* Left 2 for borders */
+ BlankStart = Display;
+
+ r[CRTbase+0x06]=Total;
+ r[CRTbase+0x07]=((Total & 0x100)>>8) | ((Display & 0x100)>>7) |
+ ((SyncStart & 0x100)>>6) | ((BlankStart & 0x100)>>5) |
+ 0x10 | ((Total & 0x200)>>4) | ((Display & 0x200)>>3) |
+ ((SyncStart & 0x200)>>2);
+ /* Number of scans before next line, VBS bit 9 and Line Compare bit 9 */
+ r[CRTbase+0x09]|=((mode->flags & 0xC)>>2) | ((BlankStart & 0x200)>>4) | 0x40;
+ r[CRTbase+0x10]=SyncStart;
+ r[CRTbase+0x11]=0x80 | (SyncEnd & 0x0F);
+ r[CRTbase+0x12]=Display-1;
+ r[CRTbase+0x15]=BlankStart;
+ r[CRTbase+0x16]=BlankEnd;
+
+ /* Line compare 0x3FF to avoid display split */
+ r[CRTbase+0x18]=0xFF;
+
+ SetForSVGAMode(mode,VirtualWidth,r,rs,Display,BlankStart,SyncStart,Total);
+}
+
+void CaptureSVGAStart(void)
+{
+ TGUI9440SaveRegs(CapturedSVGARegs);
+}
+
+uchar DefaultTXTPalette[768]={
+0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
+0x00,0x2A,0x2A,0x2A,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x15,0x00,0x00,0x3F,0x00,0x2A,
+0x15,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x2A,0x2A,0x3F,
+0x00,0x15,0x00,0x00,0x15,0x2A,0x00,0x3F,0x00,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x2A,
+0x15,0x2A,0x2A,0x3F,0x00,0x2A,0x3F,0x2A,0x00,0x15,0x15,0x00,0x15,0x3F,0x00,0x3F,
+0x15,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x2A,0x15,0x3F,0x2A,0x3F,0x15,0x2A,0x3F,0x3F,
+0x15,0x00,0x00,0x15,0x00,0x2A,0x15,0x2A,0x00,0x15,0x2A,0x2A,0x3F,0x00,0x00,0x3F,
+0x00,0x2A,0x3F,0x2A,0x00,0x3F,0x2A,0x2A,0x15,0x00,0x15,0x15,0x00,0x3F,0x15,0x2A,
+0x15,0x15,0x2A,0x3F,0x3F,0x00,0x15,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x3F,0x2A,0x3F,
+0x15,0x15,0x00,0x15,0x15,0x2A,0x15,0x3F,0x00,0x15,0x3F,0x2A,0x3F,0x15,0x00,0x3F,
+0x15,0x2A,0x3F,0x3F,0x00,0x3F,0x3F,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
+0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
+0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
+0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
+0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
+0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
+0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
+0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
+0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
+0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
+0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
+0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
+0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
+0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
+0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
+0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
+0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
+0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
+0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
+0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
+0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
+0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
+0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
+0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
+0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
+0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
+0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
+0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
+0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
+0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
+0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
+0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
+0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
+0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
+0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
+0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
+0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
+0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};
+
+void Memcpy(uchar *d, uchar *s, int size)
+{
+ while (size--)
+ *(d++)=*(s++);
+}
+
+void VGADumpRegs(uchar *regs, uchar *Sregs);
+
+/*
+ Todo: enhance the memcpy
+*/
+void SetVideoModeH(VideoModeStr *modeInfo, int width, int bpp)
+{
+ Memcpy(WorkingVGARegs,DefaultVGARegs,VGARegsCant);
+ Memcpy(WorkingSVGARegs,CapturedSVGARegs,VGARegsCant);
+ SetForVGAMode(modeInfo,width,WorkingVGARegs,WorkingSVGARegs);
+ /* Testing functions to compare registers
+ VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
+ VGALoadRegs(WorkingVGARegs,WorkingSVGARegs);
+ /* Testing functions to compare registers
+ VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
+ VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
+}
+
+
+extern unsigned *TextModeMemory;
+
+void SetTextModeVGA(void)
+{
+ int i,j;
+ unsigned *p=(unsigned *)(&VGA8x16Font[0]);
+
+ /* Testing functions to compare registers
+ VGADumpRegs(TextModeVGARegs,CapturedSVGARegs);*/
+
+ /* Set all the registers for the text mode */
+ VGALoadRegs(TextModeVGARegs,CapturedSVGARegs);
+
+ /******** Restore the fonts. It wasn't that easy to make, I had big
+ troubles to find how exactly the fonts are stored *******/
+ /* Planar mode */
+ WriteSEQ(4,6);
+ /* Plane 2 */
+ WriteSEQ(2,4);
+ /* Linear inside the plane */
+ WriteGRA(5,0);
+
+ for (i=0,j=0; i<1024; i+=4, j+=8)
+ {
+ TextModeMemory[j+0]=p[i+0];
+ TextModeMemory[j+1]=p[i+1];
+ TextModeMemory[j+2]=p[i+2];
+ TextModeMemory[j+3]=p[i+3];
+ TextModeMemory[j+4]=0;
+ TextModeMemory[j+5]=0;
+ TextModeMemory[j+6]=0;
+ TextModeMemory[j+7]=0;
+ }
+
+ /* A0 selects the bank (odd/even) */
+ WriteSEQ(4,2);
+ /* Plane 0-1 */
+ WriteSEQ(2,3);
+ /* Interlaced in the plane */
+ WriteGRA(5,0x10);
+ /************ End of font stuff ***********/
+
+ /* Clear the screen (Attribute 7 and spaces) */
+ for (i=0; i<1000; i++)
+ TextModeMemory[i]=0x07200720;
+
+ /* Restore the text mode palette (Is different to the one used for
+ graphics!!), if you use the one used in graphics mode some programs
+ look like a girl's bedroom (lot of pinks and violets ;-) */
+ RPF_SetPalRange(DefaultTXTPalette,0,256);
+
+ /* Testing functions to compare registers
+ VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
+ VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);*/
+}
+
+/*****************************************************************************
+
+ Just for testing.
+
+*****************************************************************************/
+
+
+#if 0
+void VGADumpRegs(uchar *regs, uchar *Sregs);
+
+void Set640x480x8bpp(void)
+{
+ int i;
+ Memcpy(WorkingVGARegs,DefaultVGARegs,VGARegsCant);
+ Memcpy(WorkingSVGARegs,CapturedSVGARegs,VGARegsCant);
+ //SetForVGAMode(&g576x432x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ SetForVGAMode(&g640x480x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ //SetForVGAMode(&g800x600x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ //SetForVGAMode(&g1024x768x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ //SetForVGAMode(&g320x240x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ //SetForVGAMode(&g400x300x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ //SetForVGAMode(&g1152x900x8,1024,WorkingVGARegs,WorkingSVGARegs);
+ VGALoadRegs(WorkingVGARegs,WorkingSVGARegs);
+ //VGASaveRegs(WorkingVGARegs,WorkingSVGARegs);
+ //VGADumpRegs(WorkingVGARegs,WorkingSVGARegs);
+ RPF_SetPalRange(DefaultVGAPalette,0,256);
+ for (i=0; i<122880; i++)
+ Screenl[i]=0;
+}
+#endif
diff --git a/tgui/setmode.h b/tgui/setmode.h
new file mode 100644
index 0000000..8882ff4
--- /dev/null
+++ b/tgui/setmode.h
@@ -0,0 +1,60 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/***** Flags used in the video mode structure *****/
+/* b0-b1 */
+#define NHSync 1
+#define NVSync 2
+#define PHSync 0
+#define PVSync 0
+/* b2-b3 */
+#define DoubleScan 4
+#define TripleScan 8
+#define QuadrupleScan 0xC
+/* b4-b6 */
+#define BPP8 0x00
+#define BPP15 0x10
+#define BPP16 0x20
+#define BPP24 0x30
+/* b7 */
+#define Interlaced 0x80
+/* b31 */
+#define HaveAccel2D 0x80000000
+/* This mask erase all the flags passed in the CRTC structure */
+#define InternalMask 0xFFFFFF70
+
+#define ExtractBPP(a) ((a & 0x70)>>4)
+#define is8BPP 0
+#define is15BPP 1
+#define is16BPP 2
+#define is24BPP 3
+
+/**** Video mode structure ****/
+typedef struct
+{
+ int flags;
+ ushort hDisplay,hSyncStart,hSyncEnd,hTotal;
+ ushort vDisplay,vSyncStart,vSyncEnd,vTotal;
+ ushort minBytesPerScan;
+ uchar ClockType;
+ uchar ClockValHigh,ClockValLow;
+} VideoModeStr;
+
+extern VideoModeStr *SupportedVideoModes[];
+extern int NumSupportedVideoModes;
+extern short SupportedVideoModesNums[];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void CaptureSVGAStart(void);
+void Set640x480x8bpp(void);
+int GetBestPitchFor(int BytesPerScan, int BytesPerPixel);
+void SetVideoModeH(VideoModeStr *modeInfo, int width, int bpp);
+void SetTextModeVGA(void);
+void ReadVSync(int *start, int *end);
+void SetVSync(int start, int end);
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/tgui/tgui.h b/tgui/tgui.h
new file mode 100644
index 0000000..ae312f1
--- /dev/null
+++ b/tgui/tgui.h
@@ -0,0 +1,330 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/* TGUI Alternative bank selector */
+/* It select the bank when we use a 32Kb or 64Kb window */
+#define DestinationSegmentAddress 0x3D8
+#define SourceSegmentAddress 0x3D9
+
+
+#define INLINE extern inline
+
+//#define IOMAPPED
+//#define UNDERTEST
+
+#ifdef UNDERTEST
+#include
+#endif
+
+#ifdef IOMAPPED
+#define MODEINIT 0x80
+INLINE void Putb(unsigned pos, uchar val) { outportb(0x2100+pos,val); }
+INLINE void Putw(unsigned pos, ushort val) { outportw(0x2100+pos,val); }
+INLINE void Putl(unsigned pos, unsigned val) { outportl(0x2100+pos,val); }
+INLINE uchar Getb(unsigned pos) { return inportb(0x2100+pos); }
+INLINE ushort Getw(unsigned pos) { return inportw(0x2100+pos); }
+INLINE unsigned Getl(unsigned pos) { return inportl(0x2100+pos); }
+#else
+// Memory mapped
+#define MODEINIT 0x81
+#ifdef UNDERTEST
+#define MMIOBASE 0xB7F00
+//#define MMIOBASE 0xBFF00
+//#define MODEINIT 0x82
+INLINE void Putb(unsigned pos, uchar val) { _farnspokeb(MMIOBASE+pos,val); }
+INLINE void Putw(unsigned pos, ushort val) { _farnspokew(MMIOBASE+pos,val); }
+INLINE void Putl(unsigned pos, unsigned val) { _farnspokel(MMIOBASE+pos,val); }
+INLINE uchar Getb(unsigned pos) { return _farnspeekb(MMIOBASE+pos); }
+INLINE ushort Getw(unsigned pos) { return _farnspeekw(MMIOBASE+pos); }
+INLINE unsigned Getl(unsigned pos) { return _farnspeekl(MMIOBASE+pos); }
+#else
+extern unsigned MMIOBASE;
+/*
+ If I don't use volatile the stupid gcc does funny things like that:
+ movl _MMIOBASE,%eax
+ movl 0x32(%eax),%al
+Lxxx:
+ testb %al,$0x40
+ jne Lxxx
+
+ :-)))) the silly compiler is specting some gost will change AL by magic.
+ Using volatile generates good code. Some idiot reloads are performed but
+that's normal in the "unoptimizer" module of gcc ;-)
+ Memory mapped I/O generates much compact code and I guess faster too, I
+must test it.
+*/
+INLINE void Putb(unsigned pos, uchar val) { *((volatile uchar *)(MMIOBASE+pos))=val; }
+INLINE void Putw(unsigned pos, ushort val) { *((volatile ushort *)(MMIOBASE+pos))=val; }
+INLINE void Putl(unsigned pos, unsigned val) { *((volatile unsigned *)(MMIOBASE+pos))=val; }
+INLINE uchar Getb(unsigned pos) { return *((volatile uchar *)(MMIOBASE+pos)); }
+INLINE ushort Getw(unsigned pos) { return *((volatile ushort *)(MMIOBASE+pos)); }
+INLINE unsigned Getl(unsigned pos) { return *((volatile unsigned *)(MMIOBASE+pos)); }
+#endif
+#endif
+
+// Register index
+#define GECR 0x36
+#define CLAR 0x21
+
+// ****************************** GER values ********************************
+// Status
+#define GESR 0x20
+// Operation Mode 0
+#define GOMR0 0x22
+// Operation Mode 1 (Not implemented in 9440)
+#define GOMR1 0x23
+// Command
+#define GECoR 0x24
+// Foreground Mix
+#define FMR 0x27
+// Drawing Flag 0,1,2 (Not implemented in 9440) and 3
+#define GEDFR0 0x28
+#define GEDFR1 0x29
+#define GEDFR2 0x2A
+#define GEDFR3 0x2B
+/* All joined in one 32 bits: */
+#define PatFromDisplay 0x00000002
+#define PatFromSystem 0
+#define SourceDataDisplay 0x00000004
+#define SourceDataSystem 0
+#define PatMono 0x00000020
+#define PatColor 0
+#define SourceDataMono 0x00000040
+#define SourceDataColor 0
+#define YDecreasing 0x00000100
+#define XDecreasing 0x00000200
+#define YMajor 0x00000400
+#define TransparentEnable 0x00001000
+#define TransparentReverse 0x00002000
+#define SolidDrawing 0x00004000
+#define PatternedDrawing 0
+#define PatternedLines 0x00008000
+// Foreground Color 0 (Low 8 bits) and 1
+#define FCR0 0x2C
+#define FCR1 0x2D
+// Background Color 0 (Low 8 bits) and 1
+#define BCR0 0x30
+#define BCR1 0x31
+// Pattern Location 0 (Low) and 1
+// Data must be 64 bytes aligned in VRAM, in 16 bits mode the lower bit must
+// be 0
+#define PLR0 0x34
+#define PLR1 0x35
+// Destination X Location 0 (Low) and 1
+#define DXL0 0x38
+#define DXL1 0x39
+// Destination Y Location 0 (Low) and 1
+// Only 11 bits used
+#define DYL0 0x3A
+#define DYL1 0x3B
+// Source X Location 0 (Low) and 1
+// Or diagonal step for line operations (detaY-deltaX) only 12 bits signed
+#define SXL0 0x3C
+#define SXL1 0x3D
+// Source Y Location 0 (Low) and 1
+// Or axial step for line operations (detaY) only 11 bits signed
+#define SYL0 0x3E
+#define SYL1 0x3F
+// Operation Dimension X Location 0 (Low) and 1
+// Or initial error for line operations (2*detaY-deltaX) only 12 bits signed
+#define ODXL0 0x40
+#define ODXL1 0x41
+// Operation Dimension Y Location 0 (Low) and 1
+// Or length for line operations (deltaX) only 12 bits unsigned
+// Various bits for short vector operations.
+#define ODYL0 0x42
+#define ODYL1 0x43
+// Pen Style Mask 0 and 1 for lines
+#define PSMR0 0x44
+#define PSMR1 0x45
+// Style Mask First Pixel Repeat Count for lines
+#define SMFPRC 0x46
+// Style Mask Repeat Count for lines
+#define SMRC 0x47
+// Registers 0x80 to 0xFF are for the pattern
+// ************************* End of GER values *****************************
+// ****** Commands for GECoR ******
+#define NOP 0
+#define BitBLT 1
+#define ScanLine 3
+// Bresenham Line
+#define BLine 4
+// Short vector
+#define SVector 5
+
+extern unsigned long linearAddress;
+#define Screenb ((uchar *)linearAddress)
+#define Screenw ((ushort *)linearAddress)
+#define Screenl ((unsigned *)linearAddress)
+
+#define SetXLocation(a) Putw(DXL0,a)
+#define SetYLocation(a) Putw(DYL0,a)
+#define SetXYLocation(a,b) Putl(DXL0,(a) | ((b)<<16))
+#define SetXYSource(a,b) Putl(SXL0,(a) | ((b)<<16))
+#define SetForeground(a) Putw(FCR0,a)
+#define SetBackground(a) Putw(BCR0,a)
+#define SetForegroundMix(a) Putb(FMR,a)
+#define SetPenStyleMask(a) Putw(PSMR0,a)
+#define SetStyleMaskRepeatCount(a) Putb(SMRC,a)
+
+//#define SAFE_IO
+
+INLINE
+void SetLineSteps(int deltaY, int deltaX)
+{
+ // Diagonal step is dY-dX, Axial step is dY both 16 bits signed
+ Putl(SXL0,((deltaY-deltaX) & 0xFFFF) | (deltaY<<16));
+}
+
+INLINE
+void SetErrAndLen(int deltaY, int deltaX)
+{
+ // Initial error is 2*dY-dX (signed), Length is ABS(dX) (unsigned)
+ Putl(ODXL0,((2*deltaY-deltaX) & 0xFFFF) | (deltaX<<16));
+}
+
+
+INLINE
+void SetDimensions(int width, int height)
+{
+ Putl(ODXL0,width | (height<<16));
+}
+
+INLINE
+void SetWidth_1(int width)
+{
+ Putw(ODXL0,width-1);
+}
+
+INLINE
+void SetWidth(int width)
+{
+ Putw(ODXL0,width);
+}
+
+INLINE
+void SetDrawFlags(int dir)
+{
+ Putl(GEDFR0,dir);
+}
+
+INLINE
+void SetPatternLocation(unsigned offset)
+{
+ Putw(PLR0,offset);
+}
+
+/*
+ Wait until the GER is idle. That's needed for the BitBlt operation because
+we can't write to the screen. If I return the control to the application
+and it tries to draw directly to the screen it will fail.
+ In OS drivers, line Windows drivers, that's not needed because the
+application NEVER will draw directly to the screen.
+ An additional feature not exploited is that the GER can generate interrupts
+so we can have a queue of command in memory and transfer it to the TGUI
+when the GER is ready.
+*/
+INLINE
+void WaitGE(void)
+{
+ while (Getb(GESR) & 0x80);
+}
+
+/*
+ Wait until the FIFO of the GER is empty, if we don't do it the cached
+command will use the new settings ;-)
+*/
+INLINE
+void WaitGEfifo(void)
+{
+ while (Getb(GESR) & 0x20);
+}
+
+/*
+ That's a very bad thing, I must put a full wait after the blit because
+during the Blit the CPU can't access the VRAM.
+ It could be avoided only if ALL the drawing is made by the driver, but
+that's not the FreeBE/AF case.
+*/
+INLINE
+void DoBlit(void)
+{
+ Putb(GECoR,BitBLT);
+ #ifdef WAITTILLIDLE_NOT_NEEDED
+ WaitGE();
+ #endif
+}
+
+INLINE
+void DoBlitDontWait(void)
+{
+ Putb(GECoR,BitBLT);
+}
+
+INLINE
+void DoBresenhamLine(void)
+{
+ Putb(GECoR,BLine);
+}
+
+INLINE
+void DoScan(void)
+{
+ Putb(GECoR,ScanLine);
+}
+
+INLINE
+void SetNewMode(void)
+{
+ ReadSEQ(0xB);
+}
+
+INLINE
+void SetOldMode(void)
+{
+ WriteSEQ(0xB,0);
+}
+
+/**************************** RASTER OPERATIONS ****************************/
+/* Most of them are for solid colors or patterns only */
+#define ROP_0 0x00
+#define ROP_n_PoD 0x05
+#define ROP_nPaD 0x0A
+#define ROP_nP 0x0F
+#define ROP_PanD 0x50
+#define ROP_nD 0x55
+#define ROP_PxD 0x5A
+#define ROP_n_PaD 0x5F
+#define ROP_PaD 0xA0
+#define ROP_n_PxD 0xA5
+#define ROP_D 0xAA
+#define ROP_nPoD 0xAF
+#define ROP_P 0xF0
+#define ROP_PonD 0xF5
+#define ROP_PoD 0xFA
+#define ROP_1 0xFF
+
+/* These are for image blits only */
+/* 0x00 is ROP_0 */
+#define ROP_n_SoD 0x11
+#define ROP_nSaD 0x22
+#define ROP_nS 0x33
+#define ROP_SanD 0x44
+/* 0x55 is ROP_nD */
+#define ROP_SxD 0x66
+#define ROP_n_SaD 0x77
+#define ROP_SaD 0x88
+#define ROP_n_SxD 0x99
+/* 0xAA is ROP_D */
+#define ROP_nSoD 0xBB
+#define ROP_S 0xCC
+#define ROP_SonD 0xDD
+#define ROP_SoD 0xEE
+/* 0xFF is ROP_1 */
+
+#define VClockDiv2 0x20
+#define VClockDiv4 0x40
+#define VClockDiv1_5 0x60
+#define DClockDiv2 0x80
+
+
diff --git a/tgui/vbeaf.htm b/tgui/vbeaf.htm
new file mode 100644
index 0000000..0a73d30
--- /dev/null
+++ b/tgui/vbeaf.htm
@@ -0,0 +1,1601 @@
+
+
+FreeBE/AF driver for TGUI9440AGi
+
+
+FreeBE/AF driver for TGUI9440AGi
+
+This document describes the functions implemented in the
+TGUI9440AGi's FreeBE/AF driver.
+
+
+
+This document applies to version 1.0 of the driver.
+
+
+
+
+
+
+
+
+
+
+Alphabetical List
+
+
+
+
+
+
+
+Files
+
+
+
+
+
+
+driver.c
+
+
+
+
+
+
+
+
+
+dumpreg.c
+
+
+
+
+
+
+
+
+
+rw_regs.c
+
+
+
+
+
+
+
+
+
+
+
+TestMemory (driver.c 239)
+
+Syntax
+
+
+
+
+ TestMemory();
+
+
+
+
+
+Description
+
+This function tests the video memory. I use 256Kb steps because I think
+less than it is impossible. In fact I think all the 9440 boards have 1Mb
+or 2Mb of memory. Some time ago I tried to install 1.5Mb in one board and
+the BIOS reported just 1Mb. I also tried removing 0.5Mb and the BIOS
+detected it OK. I think Trident's BIOS detects 256, 512, 1024 and 2048.
+ The first time I tested this function writing outside the memory didn't
+write, but when I tested it in my machine it made a write at the 0 position.
+The stranger thing is that it doesn't happend with unoptimized code.
+ Oh! if you wander about why such a complex test, beleive me if you don't
+check all you could detect any crazy value.
+
+
+
+
+
+
+
+Set8x8MonoPattern (driver.c 383)
+
+Syntax
+
+
+
+
+ Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern);
+
+
+
+
+
+Description
+
+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. DrawPattScan.
+DrawPattRect.
+
+
+
+
+
+
+
+Set8x8ColorPattern (driver.c 410)
+
+Syntax
+
+
+
+
+ Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern);
+
+
+
+
+
+Description
+
+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).
+DrawColorPattScan. DrawColorPattRect.
+
+// ToDo: Make 2 versions
+
+
+
+
+
+
+
+Use8x8ColorPattern (driver.c 441)
+
+Syntax
+
+
+
+
+ Use8x8ColorPattern(AF_DRIVER *af, int index);
+
+
+
+
+
+Description
+
+Selects one of the patterns previously downloaded by Set8x8ColorPattern().
+Set8x8ColorPattern.
+
+
+
+
+
+
+
+SetLineStipple (driver.c 523)
+
+Syntax
+
+
+
+
+ SetLineStipple(AF_DRIVER *af, unsigned short stipple);
+
+
+
+
+
+Description
+
+Sets the mask used for stipple lines. DrawStippleLine.
+
+
+ I'm not sure about it so here is my guess: TGUI9440 have a 16 bits
+register (GER44,GER45) to set the mask used for patterned lines so I guess
+that's this function is to setup this value.
+
+
+
+
+
+
+
+
+
+SetLineStippleCount (driver.c 542)
+
+Syntax
+
+
+
+
+ SetLineStippleCount(AF_DRIVER *af, unsigned long count);
+
+
+
+
+
+Description
+
+Sets the repeat counter for the mask used in stipple lines.
+DrawStippleLine.
+
+
+ I'm not sure about it so here is my guess: TGUI9440 have an 8 bits
+register (GER47) to set the scale of the pattern for patterned lines. A value
+of 0 means that each bit in the pattern is 1 dot, a value of 1 expands
+each pixel to 2 dots and so on.
+
+
+
+
+
+
+
+
+
+DrawStippleLine (driver.c 561)
+
+Syntax
+
+
+
+
+ DrawStippleLine(AF_DRIVER *af, unsigned long foreColor, unsigned long backColor, fixed x1, fixed y1, fixed x2, fixed y2);
+
+
+
+
+
+Description
+
+Draws a stipple line (patterned, dotted). SetLineStipple sets the pattern
+used and SetLineStippleCount the scale. SetLineStipple.
+SetLineStippleCount.
+
+
+ Note: This function doesn't call drawline, it is almost the same code
+repeated. That's to increase speed because in this way I can make the
+Bresenham parameters calculation in parallel with the GE.
+
+
+
+
+
+
+
+DrawRect (driver.c 647)
+
+Syntax
+
+
+
+
+ DrawRect(AF_DRIVER *af, unsigned long color, long left, long top, long width, long height);
+
+
+
+
+
+Description
+
+Fills a rectangle in the current foreground mix mode.
+
+
+
+
+
+
+
+DrawScan (driver.c 691)
+
+Syntax
+
+
+
+
+ DrawScan(AF_DRIVER *af, long color, long y, long x1, long x2);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+DrawPattRect (driver.c 782)
+
+Syntax
+
+
+
+
+ DrawPattRect(AF_DRIVER *af, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+DrawPattScan (driver.c 842)
+
+Syntax
+
+
+
+
+ DrawPattScan(AF_DRIVER *af, long foreColor, long backColor, long y, long x1, long x2);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+DrawColorPattRect (driver.c 957)
+
+Syntax
+
+
+
+
+ DrawColorPattRect(AF_DRIVER *af, long left, long top, long width, long height);
+
+
+
+
+
+Description
+
+Fills a rectangle using the current color pattern and mix mode.
+
+
+
+
+
+
+
+DrawColorPattScan (driver.c 982)
+
+Syntax
+
+
+
+
+ DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+BitBlt (driver.c 1069)
+
+Syntax
+
+
+
+
+ BitBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+SrcTransBlt (driver.c 1111)
+
+Syntax
+
+
+
+
+ SrcTransBlt(AF_DRIVER *af, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+BitBltSys (driver.c 1136)
+
+Syntax
+
+
+
+
+ BitBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
+
+
+
+
+
+Description
+
+Copies from system memory to the screen.
+
+
+
+
+
+
+
+SrcTransBltSys (driver.c 1196)
+
+Syntax
+
+
+
+
+ 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);
+
+
+
+
+
+Description
+
+Copies from system memory to the screen, skipping any source pixels that
+match the specified transparent color.
+
+
+
+
+
+
+
+PutMonoImage (driver.c 1256)
+
+Syntax
+
+
+
+
+ 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);
+
+
+
+
+
+Description
+
+Expands a monochrome bitmap from system memory onto the screen.
+
+
+
+
+
+
+
+DrawTrap (driver.c 1320)
+
+Syntax
+
+
+
+
+ DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap);
+
+
+
+
+
+Description
+
+Draws a filled trapezoid, using the current foreground mix mode.
+
+
+ TGUI9440 doesn't have trapezoids, I think it was introduced in 96xx chips.
+I implemented it using scan lines, I think that's faster than a software
+trapezoid.
+
+
+
+
+
+
+
+SetCursor (driver.c 1374)
+
+Syntax
+
+
+
+
+ SetCursor(AF_DRIVER *af, AF_CURSOR *cursor);
+
+
+
+
+
+Description
+
+Sets the hardware cursor shape.
+
+// ToDo split it in various
+
+
+
+
+
+
+
+SetCursorPos (driver.c 1437)
+
+Syntax
+
+
+
+
+ SetCursorPos(AF_DRIVER *af, long x, long y);
+
+
+
+
+
+Description
+
+Sets the hardware cursor position.
+
+
+
+
+
+
+
+SetCursorColor (driver.c 1476)
+
+Syntax
+
+
+
+
+ SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green, unsigned char blue);
+
+
+
+
+
+Description
+
+Sets the hardware cursor color.
+
+
+ Not supported by TGUI9440, I think 968x adds some registers for it.
+
+
+
+
+
+
+
+ShowCursor (driver.c 1498)
+
+Syntax
+
+
+
+
+ ShowCursor(AF_DRIVER *af, long visible);
+
+
+
+
+
+Description
+
+Turns the hardware cursor on or off.
+
+
+
+
+
+
+
+SetBank (driver.c 1513)
+
+Syntax
+
+
+
+
+ SetBank(AF_DRIVER *af, long bank);
+
+
+
+
+
+Description
+
+C-callable bank switch function.
+
+
+
+
+
+
+
+SetPaletteData (driver.c 1554)
+
+Syntax
+
+
+
+
+ SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT);
+
+
+
+
+
+Description
+
+Palette setting routine. Palette values are in 8 bits format because some
+boards support 8 bits DAC and not only 6 bits.
+
+
+
+
+
+
+
+GetDisplayStartStatus (driver.c 1584)
+
+Syntax
+
+
+
+
+ GetDisplayStartStatus(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Status poll for triple buffering. Not possible on the majority of
+present cards: this function is just a placeholder.
+
+
+ This must report if the Vertical Retrace Interval taked effect and the
+Display Start were transfered.
+
+
+ Lamentably TGUI9440 doesn't set 3C2.b7, that's a clear violation to the
+VGA standard, Trident people must do it, like CHIPS does.
+
+
+
+
+
+
+
+SetDisplayStart (driver.c 1601)
+
+Syntax
+
+
+
+
+ SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT);
+
+
+
+
+
+Description
+
+Hardware scrolling function. The waitVRT value may be one of:
+
+
+
+ -1 = don't set hardware, just store values for next page flip to use
+ 0 = set values and return immediately
+ 1 = set values and wait for retrace
+
+
+
+
+
+
+
+SetActiveBuffer (driver.c 1657)
+
+Syntax
+
+
+
+
+ SetActiveBuffer(AF_DRIVER *af, long index);
+
+
+
+
+
+Description
+
+Sets which buffer is being drawn onto, for use in multi buffering
+systems (not used by Allegro).
+
+
+ I took it from the prototype driver and seems to be totally independent
+of the board.
+
+
+
+
+
+
+
+SetVisibleBuffer (driver.c 1687)
+
+Syntax
+
+
+
+
+ SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT);
+
+
+
+
+
+Description
+
+Sets which buffer is displayed on the screen, for use in multi buffering
+systems (not used by Allegro).
+
+
+ Copied from the prototype driver.
+
+
+
+
+
+
+
+GetVideoModeInfo (driver.c 1704)
+
+Syntax
+
+
+
+
+ GetVideoModeInfo(AF_DRIVER *af, unsigned Mode, AF_MODE_INFO *modeInfo);
+
+
+
+
+
+Description
+
+Retrieves information about this video mode, returning zero on success
+or -1 if the mode is invalid.
+
+
+
+
+
+
+
+FindClosestVClk (driver.c 1904)
+
+Syntax
+
+
+
+
+ FindClosestVClk(unsigned fx, unsigned *VClkReg, unsigned *Divider);
+
+
+
+
+
+Description
+
+This routine calculates the closest frecuency to fx that we can achieve
+with the 9440 PLL. The values to program the chip are stored in VClkReg and
+Divider.
+
+
+
+Return Value
+
+The closest available frecuency or (unsigned)-1 if the value is outside
+the range.
+
+
+
+
+
+
+GetClosestPixelClock (driver.c 2001)
+
+Syntax
+
+
+
+
+ GetClosestPixelClock(AF_DRIVER *af, unsigned mode, unsigned long pixelClock);
+
+
+
+
+
+Description
+
+
+
+
+
+Return Value
+
+:
+ The closest value available for the board or (unsigned)-1 if the value is
+outside the range.
+
+
+
+
+
+
+SetVideoMode (driver.c 2153)
+
+Syntax
+
+
+
+
+ SetVideoMode(AF_DRIVER *af, unsigned mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc);
+
+
+
+
+
+Description
+
+Sets the video mode. This function have various features, be careful.
+
+
+ Mode is a 32 bits value, and not 16 bits as the first drafts propposed.
+Because a some nasty reasons isn't just a mode number but some sort of flags
+plus mode number. The lower 10 bits are the video mode number the rest of
+the bits have the following meaning:
+
+
+
+ 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.
+
+
+
+Most of them are self-explanatory, and others aren't very clear yet.
+
+
+The virtual screen size is requested by the virtualX/Y pair the driver will
+set a screen of at least this size, if isn't posible will return error. Note
+that the actual size could be greater. For this reason bytesPerLine is filled
+with the actual X virtual size (stride?).
+
+
+You can request more than one buffer indicating it in numBuffers, if the RAM
+isn't enough the driver will return error.
+
+
+Perhaps the hardest parameter to understand is crtc. This parameter provides
+a mechanism to allow setting the refresh rate and centering the screen. The
+mechanism is incomplet and SciTech people complements it with OEM extentions,
+I asked to make these extentions official and Kendall said he will consider
+it for Nucleus. Anyways, this pointer will be used by the driver if you use
+the 0x0800 flag, the members of the structure are:
+
+
+
+unsigned short HorizontalTotal: Total pixels, visible and not visible.
+unsigned short HorizontalSyncStart: Pixel where the horizontal sync pulse
+starts.
+unsigned short HorizontalSyncEnd: End of the pulse.
+unsigned short VerticalTotal: Total lines, visible and not.
+unsigned short VerticalSyncStart: Vertical sync pulse start.
+unsigned short VerticalSyncEnd: End of the pulse.
+unsigned char Flags: Various flags see below.
+unsigned int PixelClock: Desired pixel clock, the driver will use the
+closest available so you must check it with GetClosestPixelClock.
+GetClosestPixelClock.
+unsigned short RefreshRate: Just ignore it is for very old controllers that
+have some specific crtc register values for each mode.
+unsigned short NumBuffers: That's here only for compatibility issues related
+to VBE/AF 1.0.
+
+
+
+The possible flags are:
+
+
+
+afDoubleScan (0x0001) Enable double scanned mode.
+afInterlaced (0x0002) Enable interlaced mode.
+afHSyncNeg (0x0004) Horizontal sync is negative.
+afVSyncNeg (0x0008) Vertical sync is negative.
+
+
+
+As you can see only the X/Y resolution is set by the driver and you control
+all the rest.
+
+
+To use it you must first find information about the monitor (asking the user
+or using DDC?), then calculate the total and sync positions with the VESA
+GTF formula and the aid of GetClosestPixelClock and finally pass these values
+to the driver.
+
+
+
+Important:
+
+
+1) I don't care about LFB that's on all the time.
+2) I expanded the short mode to unsigned mode because MGL 4.05 does it.
+3) I added a propietary flag: 0x80000000: Don't set the palette. I think it
+will be replaced by some OEM extention, avoid using it.
+
+
+
+
+
+
+
+
+
+RestoreTextMode (driver.c 2390)
+
+Syntax
+
+
+
+
+ RestoreTextMode(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+
+
+
+
+Return Value
+
+to text mode, shutting down the accelerator hardware.
+
+
+
+
+
+
+EnableDirectAccess (driver.c 2413)
+
+Syntax
+
+
+
+
+ EnableDirectAccess(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Provides direct access to the video RAM. That's needed for boards where
+the accelerator blocks the use of the video RAM.
+
+
+ TGUI9440 does it only during the Blit operations so in my case I simply
+do a wait until de Graphics Engine finished your job. Note that this routine
+is here just for testing because isn't needed and isn't reported.
+
+
+
+
+Example
+
+EnableDirectAccess(af);
+ .... Draw to the screen ....
+ DisableDirectAccess(af);
+
+
+
+
+
+DisableDirectAccess (driver.c 2430)
+
+Syntax
+
+
+
+
+ DisableDirectAccess(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Disables the direct access to the video RAM. That's needed for boards
+where the accelerator blocks the use of the video RAM.
+
+
+ TGUI9440 does it only during the Blit operations so in my case this
+function does nothing. Note that this routine is here just for testing
+because isn't needed and isn't reported.
+
+
+
+
+
+
+
+WaitTillIdle (driver.c 2449)
+
+Syntax
+
+
+
+
+ WaitTillIdle(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Waits until the accelerator finished your job. That's a very important
+function. Suppose you want to draw over a rectangle made with DrawRect, how
+can you be sure you won't draw under it? Waiting until the accelerator
+finished your job.
+
+
+ What I don't fully understand is the need of both:
+Enable/DisableDirectAccess and WaitTillIdle. I saw an e-mail by Kendall
+tallking about it.
+
+
+ The TGUI9440 waits until the Graphic Engine finished all the jobs.
+
+
+
+
+
+
+
+ExtStub (driver.c 2462)
+
+Syntax
+
+
+
+
+ ExtStub();
+
+
+
+
+
+Description
+
+Vendor-specific extension hook: we don't provide any.
+
+
+
+
+
+
+
+SetupDriver (driver.c 2478)
+
+Syntax
+
+
+
+
+ SetupDriver(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+InitDriver (driver.c 2577)
+
+Syntax
+
+
+
+
+ InitDriver(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+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.
+
+
+
+
+
+
+
+InitDriver (driver.c 2669)
+
+Syntax
+
+
+
+
+ InitDriver(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+
+
+
+
+Return Value
+
+to text mode, shutting down the accelerator hardware.
+
+
+
+
+
+
+InitDriver (driver.c 2692)
+
+Syntax
+
+
+
+
+ InitDriver(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Provides direct access to the video RAM. That's needed for boards where
+the accelerator blocks the use of the video RAM.
+
+
+ TGUI9440 does it only during the Blit operations so in my case I simply
+do a wait until de Graphics Engine finished your job. Note that this routine
+is here just for testing because isn't needed and isn't reported.
+
+
+
+
+Example
+
+EnableDirectAccess(af);
+ .... Draw to the screen ....
+ DisableDirectAccess(af);
+
+
+
+
+
+InitDriver (driver.c 2709)
+
+Syntax
+
+
+
+
+ InitDriver(AF_DRIVER *af);
+
+
+
+
+
+Description
+
+Disables the direct access to the video RAM. That's needed for boards
+where the accelerator blocks the use of the video RAM.
+
+
+ TGUI9440 does it only during the Blit operations so in my case this
+function does nothing. Note that this routine is here just for testing
+because isn't needed and isn't reported.
+
+
+
+
+
+
+
+DumpValues (dumpreg.c 10)
+
+Syntax
+
+
+
+
+ DumpValues(uchar *regs, int base, int cant, int last);
+
+
+
+
+
+Description
+
+Dumps the values from the arrays to the screen.
+
+
+
+
+
+
+
+TGUI9440SaveRegs (rw_regs.c 25)
+
+Syntax
+
+
+
+
+ TGUI9440SaveRegs(uchar *regs);
+
+
+
+
+
+Description
+
+This routines captures the TGUI registers in an array. Not all are stored
+because isn't needed by now. In fact I'm storing a lot of registers that
+are not needed to store.
+
+
+
+
+
+
+
+VGASaveRegs (rw_regs.c 126)
+
+Syntax
+
+
+
+
+ VGASaveRegs(uchar *regs, uchar *Sregs);
+
+
+
+
+
+Description
+
+This function stores ALL the VGA registers in an array. Additionally it
+calls to the routine that stores the TGUI registers around 120 registers
+are stored.
+
+
+
+
+
+
+
+TGUI9440LoadRegs (rw_regs.c 174)
+
+Syntax
+
+
+
+
+ TGUI9440LoadRegs(const uchar *regs);
+
+
+
+
+
+Description
+
+Restores the TGUI registers from an array.
+
+
+
+
+
+
+
+VGALoadRegs (rw_regs.c 272)
+
+Syntax
+
+
+
+
+ VGALoadRegs(const uchar *regs, const uchar *Sregs);
+
+
+
+
+
+Description
+
+Restores the VGA registers from an array.
+
+
+
+
+
+
+
+ReadVSync (rw_regs.c 334)
+
+Syntax
+
+
+
+
+ ReadVSync(int *start, int *end);
+
+
+
+
+
+Description
+
+
+
+
+
+Return Value
+
+the vertical sync start and end values. Not optimized because I
+think that's a very strange stuff.
+
+
+
+
+
+
+SetVSync (rw_regs.c 361)
+
+Syntax
+
+
+
+
+ SetVSync(int start, int end);
+
+
+
+
+
+Description
+
+Sets the vertical sync start and end values. Not optimized because I
+think that's a very strange stuff.
+
+
+
+
+
+
+
+
+
+
diff --git a/tgui/vga.h b/tgui/vga.h
new file mode 100644
index 0000000..27ad4a7
--- /dev/null
+++ b/tgui/vga.h
@@ -0,0 +1,248 @@
+/* Copyright 1998 (c) by Salvador Eduardo Tropea
+ This code is part of the FreeBE/AF project you can use it under the
+terms and conditions of the FreeBE/AF project. */
+/* (I don't take care about mono by now) */
+/* VGA Atttibute controller */
+#define ATTindex 0x3C0
+#define ATTdataW 0x3C0
+#define ATTdataR 0x3C1
+#define ATTdir 0x3DA
+/* Miscellaneous Output Register */
+#define MORdataW 0x3C2
+#define MORdataR 0x3CC
+/* VGA Sequencer Registers */
+#define Sequencer 0x3C4
+#define SequencerIndex 0x3C4
+#define SequencerData 0x3C5
+/* VGA Palette Registers */
+#define ReadDataAddress 0x3C7
+#define WriteDataAddress 0x3C8
+#define PaletteDataRegister 0x3C9
+/* VGA Graphics Controller Registers */
+#define GraphicsController 0x3CE
+#define GraphicsControllerIndex 0x3CE
+#define GraphicsControllerData 0x3CF
+/* VGA CRT Controller Register */
+#define CRTController 0x3D4
+#define CRTControllerIndex 0x3D4
+#define CRTControllerData 0x3D5
+/* VGA Input Status Register 1 */
+#define InputStatusRegister1 0x3DA
+/* Trident's DAC/Clock */
+#define EDACindex 0x83C8
+#define EDACdata 0x83C6
+
+//#define SAFE_IO
+
+#ifdef SAFE_IO
+/* C approach, safier than my assembler ;-) */
+
+extern inline
+uchar ReadCRT(uchar index)
+{
+ outportb(CRTControllerIndex,index);
+ return inportb(CRTControllerData);
+}
+
+extern inline
+uchar ReadGRA(uchar index)
+{
+ outportb(GraphicsControllerIndex,index);
+ return inportb(GraphicsControllerData);
+}
+
+extern inline
+uchar ReadSEQ(uchar index)
+{
+ outportb(SequencerIndex,index);
+ return inportb(SequencerData);
+}
+
+extern inline
+void WriteCRT(uchar index, uchar value)
+{
+ outportb(CRTControllerIndex,index);
+ outportb(CRTControllerData,value);
+}
+
+
+extern inline
+void WriteGRA(uchar index, uchar value)
+{
+ outportb(GraphicsControllerIndex,index);
+ outportb(GraphicsControllerData,value);
+}
+
+extern inline
+void WriteSEQ(uchar index, uchar value)
+{
+ outportb(SequencerIndex,index);
+ outportb(SequencerData,value);
+}
+
+extern inline
+void WaitVRT()
+{
+ while (inportb(InputStatusRegister1) & 8);
+ while (!(inportb(InputStatusRegister1) & 8));
+}
+
+#else
+/*
+ Assembler stuff: It is normally more compact and in some cases faster. As
+ the functions are inline I think size is important.
+ They save 524 bytes in the driver (1.89%).
+*/
+
+extern inline
+uchar ReadCRT(uchar index)
+{
+ uchar a asm("%eax");
+ a=index;
+ asm volatile ("
+ outb %%al,%%dx
+ incl %%edx
+ inb %%dx,%%al
+ " : "a=" (a) : "a" (a), "d" (CRTController) : "%edx");
+ return a;
+}
+
+
+extern inline
+uchar ReadGRA(uchar index)
+{
+ uchar a asm("%eax");
+ a=index;
+ asm volatile ("
+ outb %%al,%%dx
+ incl %%edx
+ inb %%dx,%%al
+ " : "a=" (a) : "a" (a), "d" (GraphicsController) : "%edx");
+ return a;
+}
+
+extern inline
+uchar ReadSEQ(uchar index)
+{
+ uchar a asm("%eax");
+ a=index;
+ asm volatile ("
+ outb %%al,%%dx
+ incl %%edx
+ inb %%dx,%%al
+ " : "a=" (a) : "a" (a), "d" (Sequencer) : "%edx");
+ return a;
+}
+
+extern inline
+void WriteCRT(uchar index, uchar value)
+{
+ asm volatile ("
+ movb %0,%%ah
+ outw %%ax,%%dx
+ " : : "qi" (value), "a" (index), "d" (CRTController) : "%eax");
+}
+
+extern inline
+void WriteGRA(uchar index, uchar value)
+{
+ asm volatile ("
+ movb %0,%%ah
+ outw %%ax,%%dx
+ " : : "qi" (value), "a" (index), "d" (GraphicsController) : "%eax");
+}
+
+extern inline
+void WriteSEQ(uchar index, uchar value)
+{
+ asm volatile ("
+ movb %0,%%ah
+ outw %%ax,%%dx
+ " : : "qi" (value), "a" (index), "d" (Sequencer) : "%eax");
+}
+
+
+extern inline
+void WaitVRT()
+{
+ asm("
+ 1:
+ inb %%dx,%%al
+ testb $8,%%al
+ jne 1b
+ .align 2,0x90
+ 2:
+ inb %%dx,%%al
+ testb $8,%%al
+ je 2b
+ " : : "d" (InputStatusRegister1) : "%eax" );
+}
+
+#endif
+
+extern inline
+uchar ReadATT(int index)
+{
+ /* Ensure we will write to the index */
+ inportb(ATTdir);
+ /* Set the index and disable the screen or we will read nothing */
+ outportb(ATTindex,index);
+ return inportb(ATTdataR);
+}
+
+extern inline
+void ATTEndReads(void)
+{
+ /* Ensure we will write to the index */
+ inportb(ATTdir);
+ /* Enable the screen */
+ outportb(ATTindex,0x20);
+}
+
+extern inline
+void WriteATT(int index, int val)
+{
+ outportb(ATTindex,index);
+ outportb(ATTdataW,val);
+}
+
+extern inline
+uchar ReadMOR(void)
+{
+ return inportb(MORdataR);
+}
+
+extern inline
+void WriteMOR(int val)
+{
+ outportb(MORdataW,val);
+}
+
+extern inline
+uchar ReadEDAC(int index)
+{
+ outportb(EDACindex,index);
+ return inportb(EDACdata);
+}
+
+extern inline
+void WriteEDAC(int index, int val)
+{
+ outportb(EDACindex,index);
+ outportb(EDACdata,val);
+}
+
+extern inline
+void RPF_SetPalRange(unsigned char *_pal_ptr, int color, int cant)
+{
+__asm__("
+ outb %%al,%%dx
+ incl %%edx
+ cli
+ rep
+ outsb
+ sti"
+: : "c" (cant*3), "S" (_pal_ptr), "a" (color), "d" (0x3C8)
+: "%eax", "%ecx", "%edx", "%esi");
+}
+
diff --git a/trident/driver.c b/trident/driver.c
new file mode 100644
index 0000000..6e8ce60
--- /dev/null
+++ b/trident/driver.c
@@ -0,0 +1,673 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Trident driver (based on the Allegro Trident code).
+ *
+ * By Shawn Hargreaves and Mark Habersack.
+ *
+ * See freebe.txt for copyright information.
+ */
+
+
+// #define NO_HWPTR
+
+
+#include
+
+#include "vbeaf.h"
+
+
+
+/* chipset information */
+int chip_id = 0;
+
+
+char *descriptions[] =
+{
+ "TVGA 8900CL/D", "TVGA 9000i", "TVGA 9200CXr",
+ "TVGA LCD9100B", "TVGA GUI9420", "TVGA LX8200", "TVGA 9400CXi",
+ "TVGA LCD9320", "Unknown", "TVGA GUI9420", "TVGA GUI9660",
+ "TVGA GUI9440", "TVGA GUI9430", "TVGA 9000C"
+};
+
+
+#define TV_LAST 13
+
+
+
+/* driver function prototypes */
+void DualSetBank32();
+void DualSetBank32End();
+void DualSetBank(AF_DRIVER *af, long bank);
+void SingleSetBank32();
+void SingleSetBank32End();
+void SingleSetBank(AF_DRIVER *af, long bank);
+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);
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+} VIDEO_MODE;
+
+
+VIDEO_MODE mode_list[] =
+{
+ { 640, 400, 8, 0x5C },
+ { 640, 480, 8, 0x5D },
+ { 800, 600, 8, 0x5E },
+ { 1024, 768, 8, 0x62 }
+};
+
+
+#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_modes[NUM_MODES+1] = { 1, 2, 3, 4, -1 };
+
+
+
+/* detect:
+ * Detects the presence of a Trident card.
+ */
+char *detect(unsigned long *vidmem)
+{
+ int old1, old2, val;
+ char *name = NULL;
+
+ old1 = read_vga_register(0x3C4, 0x0B);
+ write_vga_register(0x3C4, 0x0B, 0); /* force old mode registers */
+ chip_id = inportb(0x3C5); /* now we have the ID */
+
+ old2 = read_vga_register(0x3C4, 0x0E);
+ outportb(0x3C4+1, old2^0x55);
+ val = inportb(0x3C5);
+ outportb(0x3C5, old2);
+
+ if (((val^old2) & 0x0F) == 7) { /* if bit 2 is inverted... */
+ outportb(0x3C5, old2^2); /* we're dealing with Trident */
+
+ if (chip_id <= 2) /* don't like 8800 chips */
+ return FALSE;
+
+ val = read_vga_register(0x3D4, 0x1F); /* determine the memory size */
+ switch (val & 3) {
+ case 0: *vidmem = 256; break;
+ case 1: *vidmem = 512; break;
+ case 2: *vidmem = 768; break;
+ case 3: if ((chip_id >= 0x33) && (val & 4))
+ *vidmem = 2048;
+ else
+ *vidmem = 1024;
+ break;
+ }
+
+ /* provide user with a description of the chip s/he has */
+ if ((chip_id == 0x33) && (read_vga_register(0x3D4, 0x28) & 0x80))
+ /* is it TVGA 9000C */
+ name = descriptions[TV_LAST];
+ else if (chip_id >= 0x33)
+ name = descriptions[((chip_id & 0xF0) >> 4) - 3];
+ else {
+ switch (chip_id) {
+ case 3: name = "TR 8900B"; break;
+ case 4: name = "TVGA 8900C"; break;
+ case 0x13: name = "TVGA 8900C"; break;
+ case 0x23: name = "TR 9000"; break;
+ default: name = "Unknown"; break;
+ }
+ }
+
+ return name;
+ }
+
+ write_vga_register(0x3C4, 0x0B, old1);
+ return NULL;
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ char *name;
+ int i;
+
+ name = detect(&af->TotalMemory);
+
+ if (!name)
+ return 1;
+
+ i = 0;
+ while (af->OemVendorName[i])
+ i++;
+
+ af->OemVendorName[i++] = ',';
+ af->OemVendorName[i++] = ' ';
+
+ while (*name)
+ af->OemVendorName[i++] = *(name++);
+
+ af->OemVendorName[i] = 0;
+
+ af->AvailableModes = available_modes;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ if (chip_id >= 0x33) {
+ af->SetBank = DualSetBank;
+ af->SetBank32 = DualSetBank32;
+ af->SetBank32Len = (long)DualSetBank32End - (long)DualSetBank32;
+ }
+ else {
+ af->SetBank = SingleSetBank;
+ af->SetBank32 = SingleSetBank32;
+ af->SetBank32Len = (long)SingleSetBank32End - (long)SingleSetBank32;
+ }
+
+ 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;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ long available_vram;
+ long used_vram;
+ int width;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo, linear framebuffer, or noclear */
+ if (mode & 0xC400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > NUM_MODES))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ /* call BIOS to set the mode */
+ r.x.ax = info->num;
+ rm_int(0x10, &r);
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX > info->w) {
+ if (virtualX > 1024)
+ return -1;
+
+ *bytesPerLine = ((virtualX*BYTES_PER_PIXEL(info->bpp))+15)&0xFFF0;
+
+ width = read_vga_register(0x3D4, 0x13);
+ write_vga_register(0x3D4, 0x13, (width * (*bytesPerLine)) / (info->w*BYTES_PER_PIXEL(info->bpp)));
+ }
+ else
+ *bytesPerLine = info->w*BYTES_PER_PIXEL(info->bpp);
+
+ /* set up some hardware registers */
+ if (chip_id >= 0x33)
+ write_vga_register(0x3CE, 0x0F, 5); /* read/write banks */
+ else
+ read_vga_register(0x3C4, 0x0B); /* switch to new mode */
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = ((x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width)) >> 2;
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* first set the standard CRT Start registers */
+ outportw(0x3D4, (a & 0xFF00) | 0x0C);
+ outportw(0x3D4, ((a & 0x00FF) << 8) | 0x0D);
+
+ /* set bit 16 of the screen start address */
+ outportb(0x3D4, 0x1E);
+ outportb(0x3D5, (inportb(0x3D5) & 0xDF) | ((a & 0x10000) >> 11) );
+
+ /* bits 17-19 of the start address: uses the 8900CL/D+ register */
+ outportb(0x3D4, 0x27);
+ outportb(0x3D5, (inportb(0x3D5) & 0xF8) | ((a & 0xE0000) >> 17) );
+
+ /* set pel register */
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ write_vga_register(0x3C0, 0x33, x&3);
+
+ asm volatile ("sti");
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i
+
+#include "vbeaf.h"
+
+
+
+/* chipset information */
+#define ET_NONE 0
+#define ET_3000 1
+#define ET_4000 2
+#define ET_6000 3
+
+int tseng_type = ET_NONE;
+
+
+
+/* driver function prototypes */
+void ET3000SetBank32();
+void ET3000SetBank32End();
+void ET3000SetBank(AF_DRIVER *af, long bank);
+void ET4000SetBank32();
+void ET4000SetBank32End();
+void ET4000SetBank(AF_DRIVER *af, long bank);
+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);
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+ int bios;
+} VIDEO_MODE;
+
+
+VIDEO_MODE et3000_mode_list[] =
+{
+ { 640, 350, 8, 0x2D, 0 },
+ { 640, 480, 8, 0x2E, 0 },
+ { 800, 600, 8, 0x30, 0 }
+};
+
+
+VIDEO_MODE et4000_mode_list[] =
+{
+ { 640, 350, 8, 0x2D, 0 },
+ { 640, 480, 8, 0x2E, 0 },
+ { 640, 400, 8, 0x2F, 0 },
+ { 800, 600, 8, 0x30, 0 },
+ { 1024, 768, 8, 0x38, 0 },
+ { 320, 200, 15, 0x13, 0x10F0 },
+ { 640, 350, 15, 0x2D, 0x10F0 },
+ { 640, 480, 15, 0x2E, 0x10F0 },
+ { 640, 400, 15, 0x2F, 0x10F0 },
+ { 800, 600, 15, 0x30, 0x10F0 },
+ { 1024, 768, 15, 0x38, 0x10F0 },
+ { 640, 350, 24, 0x2DFF, 0x10F0 },
+ { 640, 480, 24, 0x2EFF, 0x10F0 },
+ { 640, 400, 24, 0x2FFF, 0x10F0 },
+ { 800, 600, 24, 0x30FF, 0x10F0 }
+};
+
+
+#define NUM_ET3000_MODES (int)(sizeof(et3000_mode_list)/sizeof(VIDEO_MODE))
+#define NUM_ET4000_MODES (int)(sizeof(et4000_mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_et3000_modes[NUM_ET3000_MODES+1] = { 1, 2, 3, -1 };
+short available_et4000_modes[NUM_ET4000_MODES+1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1 };
+
+
+
+/* detect:
+ * Detects the presence of a Tseng card.
+ */
+int detect()
+{
+ int old1, old2, subver;
+
+ old1 = inportb(0x3BF);
+ old2 = inportb(0x3D4+4);
+
+ outportb(0x3BF, 3);
+ outportb(0x3D4+4, 0xA0);
+
+ if (test_register(0x3CD, 0x3F)) {
+ if (test_vga_register(0x3D4, 0x33, 0x0F)) {
+ if (test_register(0x3CB, 0x33)) {
+ subver = read_vga_register(0x217A, 0xEC) >> 4;
+ if (subver <= 11)
+ return ET_4000;
+ else if (subver == 15)
+ return ET_6000;
+ /* else unknown Tseng */
+ }
+ else
+ return ET_4000;
+ }
+ else
+ return ET_3000;
+ }
+
+ outportb(0x3BF, old1);
+ outportb(0x3D4+4, old2);
+
+ return ET_NONE;
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ char *name = NULL;
+ int vram_size;
+ int i;
+
+ tseng_type = detect();
+
+ switch (tseng_type) {
+
+ case ET_3000:
+ name = "ET3000";
+ break;
+
+ case ET_4000:
+ name = "ET4000";
+ break;
+
+ case ET_6000:
+ name = "ET6000";
+ break;
+
+ default:
+ return 1;
+ }
+
+ i = 0;
+ while (af->OemVendorName[i])
+ i++;
+
+ af->OemVendorName[i++] = ',';
+ af->OemVendorName[i++] = ' ';
+
+ while (*name)
+ af->OemVendorName[i++] = *(name++);
+
+ af->OemVendorName[i] = 0;
+
+ if (get_vesa_info(&vram_size, NULL, NULL) != 0) {
+ if (tseng_type == ET_3000)
+ af->TotalMemory = 512;
+ else
+ af->TotalMemory = 1024;
+ }
+ else {
+ if (tseng_type == ET_3000)
+ af->TotalMemory = MIN(vram_size/1024, 512);
+ else
+ af->TotalMemory = MIN(vram_size/1024, 1024);
+ }
+
+ if (tseng_type == ET_3000) {
+ af->AvailableModes = available_et3000_modes;
+
+ af->SetBank32 = ET3000SetBank32;
+ af->SetBank32Len = (long)ET3000SetBank32End - (long)ET3000SetBank32;
+ af->SetBank = ET3000SetBank;
+ }
+ else {
+ af->AvailableModes = available_et4000_modes;
+
+ af->SetBank32 = ET4000SetBank32;
+ af->SetBank32Len = (long)ET4000SetBank32End - (long)ET4000SetBank32;
+ af->SetBank = ET4000SetBank;
+ }
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ 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;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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 > ((tseng_type == ET_3000) ? NUM_ET3000_MODES : NUM_ET4000_MODES)))
+ return -1;
+
+ if (tseng_type == ET_3000)
+ info = &et3000_mode_list[mode-1];
+ else
+ info = &et4000_mode_list[mode-1];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ long available_vram;
+ long used_vram;
+ int width;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo, linear framebuffer, or noclear */
+ if (mode & 0xC400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > ((tseng_type == ET_3000) ? NUM_ET3000_MODES : NUM_ET4000_MODES)))
+ return -1;
+
+ if (tseng_type == ET_3000)
+ info = &et3000_mode_list[mode-1];
+ else
+ info = &et4000_mode_list[mode-1];
+
+ /* call BIOS to set the mode */
+ if (info->bios) {
+ r.x.ax = info->bios;
+ r.x.bx = info->num;
+ }
+ else
+ r.x.ax = info->num;
+
+ rm_int(0x10, &r);
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX > info->w) {
+ if (virtualX > 1024)
+ return -1;
+
+ *bytesPerLine = ((virtualX*BYTES_PER_PIXEL(info->bpp))+15)&0xFFF0;
+
+ width = read_vga_register(0x3D4, 0x13);
+ write_vga_register(0x3D4, 0x13, (width * (*bytesPerLine)) / (info->w*BYTES_PER_PIXEL(info->bpp)));
+ }
+ else
+ *bytesPerLine = info->w*BYTES_PER_PIXEL(info->bpp);
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* write high bit(s) to Tseng-specific registers */
+ if (tseng_type == ET_3000)
+ alter_vga_register(0x3D4, 0x23, 2, a>>17);
+ else if (tseng_type == ET_4000)
+ alter_vga_register(0x3D4, 0x33, 3, a>>18);
+ else if (tseng_type == ET_6000)
+ alter_vga_register(0x3D4, 0x33, 3, a>>17);
+
+ /* write to normal VGA address registers */
+ write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
+ write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
+
+ asm volatile ("sti");
+
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ /* write low 2 bits to VGA horizontal pan register */
+ if (af_bpp == 8)
+ write_vga_register(0x3C0, 0x33, a&3);
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i
+
+
+#define NULL 0
+
+#define TRUE 1
+#define FALSE 0
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MID(x,y,z) MAX((x), MIN((y), (z)))
+
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+
+#define BYTES_PER_PIXEL(bpp) (((int)(bpp) + 7) / 8)
+
+typedef long fixed;
+
+
+#endif
+
+
+
+/* mode attribute flags */
+#define afHaveMultiBuffer 0x0001 /* multiple buffers */
+#define afHaveVirtualScroll 0x0002 /* virtual scrolling */
+#define afHaveBankedBuffer 0x0004 /* supports banked framebuffer */
+#define afHaveLinearBuffer 0x0008 /* supports linear framebuffer */
+#define afHaveAccel2D 0x0010 /* supports 2D acceleration */
+#define afHaveDualBuffers 0x0020 /* uses dual buffers */
+#define afHaveHWCursor 0x0040 /* supports a hardware cursor */
+#define afHave8BitDAC 0x0080 /* 8 bit palette DAC */
+#define afNonVGAMode 0x0100 /* not a VGA mode */
+#define afHaveDoubleScan 0x0200 /* supports double scanning */
+#define afHaveInterlaced 0x0400 /* supports interlacing */
+#define afHaveTripleBuffer 0x0800 /* supports triple buffering */
+#define afHaveStereo 0x1000 /* supports stereo LCD glasses */
+#define afHaveROP2 0x2000 /* supports ROP2 mix codes */
+#define afHaveHWStereoSync 0x4000 /* hardware stereo signalling */
+#define afHaveEVCStereoSync 0x8000 /* HW stereo sync via EVC connector */
+
+
+
+/* drawing modes */
+typedef enum
+{
+ AF_FORE_MIX = 0, /* background pixels use the foreground mix */
+ AF_REPLACE_MIX = 0, /* solid drawing mode */
+ AF_AND_MIX, /* bitwise AND mode */
+ AF_OR_MIX, /* bitwise OR mode */
+ AF_XOR_MIX, /* bitwise XOR mode */
+ AF_NOP_MIX, /* nothing is drawn */
+
+ /* below here need only be supported if you set the afHaveROP2 flag */
+ AF_R2_BLACK = 0x10,
+ AF_R2_NOTMERGESRC,
+ AF_R2_MASKNOTSRC,
+ AF_R2_NOTCOPYSRC,
+ AF_R2_MASKSRCNOT,
+ AF_R2_NOT,
+ AF_R2_XORSRC,
+ AF_R2_NOTMASKSRC,
+ AF_R2_MASKSRC,
+ AF_R2_NOTXORSRC,
+ AF_R2_NOP,
+ AF_R2_MERGENOTSRC,
+ AF_R2_COPYSRC,
+ AF_R2_MERGESRCNOT,
+ AF_R2_MERGESRC,
+ AF_R2_WHITE,
+} AF_mixModes;
+
+
+
+/* fixed point coordinate pair */
+typedef struct AF_FIX_POINT
+{
+ fixed x;
+ fixed y;
+} AF_FIX_POINT;
+
+
+
+/* trapezium information block */
+typedef struct AF_TRAP
+{
+ unsigned long y;
+ unsigned long count;
+ fixed x1;
+ fixed x2;
+ fixed slope1;
+ fixed slope2;
+} AF_TRAP;
+
+
+
+/* hardware cursor description */
+typedef struct AF_CURSOR
+{
+ unsigned long xorMask[32];
+ unsigned long andMask[32];
+ unsigned long hotx;
+ unsigned long hoty;
+} AF_CURSOR;
+
+
+
+/* color value */
+typedef struct AF_PALETTE
+{
+ unsigned char blue;
+ unsigned char green;
+ unsigned char red;
+ unsigned char alpha;
+} AF_PALETTE;
+
+
+
+/* CRTC information block for refresh rate control */
+typedef struct AF_CRTCInfo
+{
+ unsigned short HorizontalTotal __attribute__ ((packed)); /* horizontal total (pixels) */
+ unsigned short HorizontalSyncStart __attribute__ ((packed)); /* horizontal sync start position */
+ unsigned short HorizontalSyncEnd __attribute__ ((packed)); /* horizontal sync end position */
+ unsigned short VerticalTotal __attribute__ ((packed)); /* vertical total (lines) */
+ unsigned short VerticalSyncStart __attribute__ ((packed)); /* vertical sync start position */
+ unsigned short VerticalSyncEnd __attribute__ ((packed)); /* vertical sync end position */
+ unsigned char Flags __attribute__ ((packed)); /* initialisation flags for mode */
+ unsigned int PixelClock __attribute__ ((packed)); /* pixel clock in units of Hz */
+ unsigned short RefreshRate __attribute__ ((packed)); /* expected refresh rate in .01Hz */
+ unsigned short NumBuffers __attribute__ ((packed)); /* number of display buffers */
+} AF_CRTCInfo;
+
+
+
+/* definitions for CRTC information block flags */
+#define afDoubleScan 0x0001 /* enable double scanned mode */
+#define afInterlaced 0x0002 /* enable interlaced mode */
+#define afHSyncNeg 0x0004 /* horizontal sync is negative */
+#define afVSyncNeg 0x0008 /* vertical sync is negative */
+
+
+
+typedef unsigned char AF_PATTERN; /* pattern array elements */
+typedef unsigned AF_STIPPLE; /* 16 bit line stipple pattern */
+typedef unsigned AF_COLOR; /* packed color values */
+
+
+
+/* mode information structure */
+typedef struct AF_MODE_INFO
+{
+ unsigned short Attributes __attribute__ ((packed));
+ unsigned short XResolution __attribute__ ((packed));
+ unsigned short YResolution __attribute__ ((packed));
+ unsigned short BytesPerScanLine __attribute__ ((packed));
+ unsigned short BitsPerPixel __attribute__ ((packed));
+ unsigned short MaxBuffers __attribute__ ((packed));
+ unsigned char RedMaskSize __attribute__ ((packed));
+ unsigned char RedFieldPosition __attribute__ ((packed));
+ unsigned char GreenMaskSize __attribute__ ((packed));
+ unsigned char GreenFieldPosition __attribute__ ((packed));
+ unsigned char BlueMaskSize __attribute__ ((packed));
+ unsigned char BlueFieldPosition __attribute__ ((packed));
+ unsigned char RsvdMaskSize __attribute__ ((packed));
+ unsigned char RsvdFieldPosition __attribute__ ((packed));
+ unsigned short MaxBytesPerScanLine __attribute__ ((packed));
+ unsigned short MaxScanLineWidth __attribute__ ((packed));
+
+ /* VBE/AF 2.0 extensions */
+ unsigned short LinBytesPerScanLine __attribute__ ((packed));
+ unsigned char BnkMaxBuffers __attribute__ ((packed));
+ unsigned char LinMaxBuffers __attribute__ ((packed));
+ unsigned char LinRedMaskSize __attribute__ ((packed));
+ unsigned char LinRedFieldPosition __attribute__ ((packed));
+ unsigned char LinGreenMaskSize __attribute__ ((packed));
+ unsigned char LinGreenFieldPosition __attribute__ ((packed));
+ unsigned char LinBlueMaskSize __attribute__ ((packed));
+ unsigned char LinBlueFieldPosition __attribute__ ((packed));
+ unsigned char LinRsvdMaskSize __attribute__ ((packed));
+ unsigned char LinRsvdFieldPosition __attribute__ ((packed));
+ unsigned long MaxPixelClock __attribute__ ((packed));
+ unsigned long VideoCapabilities __attribute__ ((packed));
+ unsigned short VideoMinXScale __attribute__ ((packed));
+ unsigned short VideoMinYScale __attribute__ ((packed));
+ unsigned short VideoMaxXScale __attribute__ ((packed));
+ unsigned short VideoMaxYScale __attribute__ ((packed));
+
+ unsigned char reserved[76] __attribute__ ((packed));
+
+} AF_MODE_INFO;
+
+
+
+#define DC struct AF_DRIVER *dc
+
+
+
+/* main VBE/AF driver structure */
+typedef struct AF_DRIVER
+{
+ /* header */
+ char Signature[12] __attribute__ ((packed));
+ unsigned long Version __attribute__ ((packed));
+ unsigned long DriverRev __attribute__ ((packed));
+ char OemVendorName[80] __attribute__ ((packed));
+ char OemCopyright[80] __attribute__ ((packed));
+ short *AvailableModes __attribute__ ((packed));
+ unsigned long TotalMemory __attribute__ ((packed));
+ unsigned long Attributes __attribute__ ((packed));
+ unsigned long BankSize __attribute__ ((packed));
+ unsigned long BankedBasePtr __attribute__ ((packed));
+ unsigned long LinearSize __attribute__ ((packed));
+ unsigned long LinearBasePtr __attribute__ ((packed));
+ unsigned long LinearGranularity __attribute__ ((packed));
+ unsigned short *IOPortsTable __attribute__ ((packed));
+ unsigned long IOMemoryBase[4] __attribute__ ((packed));
+ unsigned long IOMemoryLen[4] __attribute__ ((packed));
+ unsigned long LinearStridePad __attribute__ ((packed));
+ unsigned short PCIVendorID __attribute__ ((packed));
+ unsigned short PCIDeviceID __attribute__ ((packed));
+ unsigned short PCISubSysVendorID __attribute__ ((packed));
+ unsigned short PCISubSysID __attribute__ ((packed));
+ unsigned long Checksum __attribute__ ((packed));
+ unsigned long res2[6] __attribute__ ((packed));
+
+ /* near pointers mapped by the application */
+ void *IOMemMaps[4] __attribute__ ((packed));
+ void *BankedMem __attribute__ ((packed));
+ void *LinearMem __attribute__ ((packed));
+ unsigned long res3[5] __attribute__ ((packed));
+
+ /* driver state variables */
+ unsigned long BufferEndX __attribute__ ((packed));
+ unsigned long BufferEndY __attribute__ ((packed));
+ unsigned long OriginOffset __attribute__ ((packed));
+ unsigned long OffscreenOffset __attribute__ ((packed));
+ unsigned long OffscreenStartY __attribute__ ((packed));
+ unsigned long OffscreenEndY __attribute__ ((packed));
+ unsigned long res4[10] __attribute__ ((packed));
+
+ /* relocatable 32 bit bank switch routine, for Windows (ugh!) */
+ unsigned long SetBank32Len __attribute__ ((packed));
+ void *SetBank32 __attribute__ ((packed));
+
+ /* callback functions provided by the application */
+ void *Int86 __attribute__ ((packed));
+ void *CallRealMode __attribute__ ((packed));
+
+ /* main driver setup routine */
+ void *InitDriver __attribute__ ((packed));
+
+ /* VBE/AF 1.0 asm interface (obsolete and not supported by Allegro) */
+ void *af10Funcs[40] __attribute__ ((packed));
+
+ /* VBE/AF 2.0 extensions */
+ void *PlugAndPlayInit __attribute__ ((packed));
+
+ /* extension query function, specific to FreeBE/AF */
+ void *(*OemExt)(DC, unsigned long id);
+
+ /* extension hook for implementing additional VESA interfaces */
+ void *SupplementalExt __attribute__ ((packed));
+
+ /* device driver functions */
+ long (*GetVideoModeInfo)(DC, short mode, AF_MODE_INFO *modeInfo);
+ long (*SetVideoMode)(DC, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc);
+ void (*RestoreTextMode)(DC);
+ long (*GetClosestPixelClock)(DC, short mode, unsigned long pixelClock);
+ void (*SaveRestoreState)(DC, int subfunc, void *saveBuf);
+ void (*SetDisplayStart)(DC, long x, long y, long waitVRT);
+ void (*SetActiveBuffer)(DC, long index);
+ void (*SetVisibleBuffer)(DC, long index, long waitVRT);
+ int (*GetDisplayStartStatus)(DC);
+ void (*EnableStereoMode)(DC, int enable);
+ void (*SetPaletteData)(DC, AF_PALETTE *pal, long num, long index, long waitVRT);
+ void (*SetGammaCorrectData)(DC, AF_PALETTE *pal, long num, long index);
+ void (*SetBank)(DC, long bank);
+
+ /* hardware cursor functions */
+ void (*SetCursor)(DC, AF_CURSOR *cursor);
+ void (*SetCursorPos)(DC, long x, long y);
+ void (*SetCursorColor)(DC, unsigned char red, unsigned char green, unsigned char blue);
+ void (*ShowCursor)(DC, long visible);
+
+ /* 2D rendering functions */
+ void (*WaitTillIdle)(DC);
+ void (*EnableDirectAccess)(DC);
+ void (*DisableDirectAccess)(DC);
+ void (*SetMix)(DC, long foreMix, long backMix);
+ void (*Set8x8MonoPattern)(DC, unsigned char *pattern);
+ void (*Set8x8ColorPattern)(DC, int index, unsigned long *pattern);
+ void (*Use8x8ColorPattern)(DC, int index);
+ void (*SetLineStipple)(DC, unsigned short stipple);
+ void (*SetLineStippleCount)(DC, unsigned long count);
+ void (*SetClipRect)(DC, long minx, long miny, long maxx, long maxy);
+ void (*DrawScan)(DC, long color, long y, long x1, long x2);
+ void (*DrawPattScan)(DC, long foreColor, long backColor, long y, long x1, long x2);
+ void (*DrawColorPattScan)(DC, long y, long x1, long x2);
+ void (*DrawScanList)(DC, unsigned long color, long y, long length, short *scans);
+ void (*DrawPattScanList)(DC, unsigned long foreColor, unsigned long backColor, long y, long length, short *scans);
+ void (*DrawColorPattScanList)(DC, long y, long length, short *scans);
+ void (*DrawRect)(DC, unsigned long color, long left, long top, long width, long height);
+ void (*DrawPattRect)(DC, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height);
+ void (*DrawColorPattRect)(DC, long left, long top, long width, long height);
+ void (*DrawLine)(DC, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2);
+ void (*DrawStippleLine)(DC, unsigned long foreColor, unsigned long backColor, fixed x1, fixed y1, fixed x2, fixed y2);
+ void (*DrawTrap)(DC, unsigned long color, AF_TRAP *trap);
+ void (*DrawTri)(DC, unsigned long color, AF_FIX_POINT *v1, AF_FIX_POINT *v2, AF_FIX_POINT *v3, fixed xOffset, fixed yOffset);
+ void (*DrawQuad)(DC, unsigned long color, AF_FIX_POINT *v1, AF_FIX_POINT *v2, AF_FIX_POINT *v3, AF_FIX_POINT *v4, fixed xOffset, fixed yOffset);
+ void (*PutMonoImage)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, unsigned char *image);
+ void (*PutMonoImageLin)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imageOfs);
+ void (*PutMonoImageBM)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imagePhysAddr);
+ void (*BitBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op);
+ void (*BitBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
+ void (*BitBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
+ void (*BitBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
+ void (*SrcTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*SrcTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*SrcTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*SrcTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*DstTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*DstTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*DstTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*DstTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
+ void (*StretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op);
+ void (*StretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op);
+ void (*StretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op);
+ void (*StretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op);
+ void (*SrcTransStretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*SrcTransStretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*SrcTransStretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*SrcTransStretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*DstTransStretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*DstTransStretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*DstTransStretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+ void (*DstTransStretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent);
+
+ /* hardware video functions */
+ void (*SetVideoInput)(DC, long width, long height, long format);
+ void *(*SetVideoOutput)(DC, long left, long top, long width, long height);
+ void (*StartVideoFrame)(DC);
+ void (*EndVideoFrame)(DC);
+
+} AF_DRIVER;
+
+
+
+#undef DC
+
+
+
+/* register data for calling real mode interrupts (DPMI format) */
+typedef union
+{
+ struct {
+ unsigned long edi;
+ unsigned long esi;
+ unsigned long ebp;
+ unsigned long res;
+ unsigned long ebx;
+ unsigned long edx;
+ unsigned long ecx;
+ unsigned long eax;
+ } d;
+ struct {
+ unsigned short di, di_hi;
+ unsigned short si, si_hi;
+ unsigned short bp, bp_hi;
+ unsigned short res, res_hi;
+ unsigned short bx, bx_hi;
+ unsigned short dx, dx_hi;
+ unsigned short cx, cx_hi;
+ unsigned short ax, ax_hi;
+ unsigned short flags;
+ unsigned short es;
+ unsigned short ds;
+ unsigned short fs;
+ unsigned short gs;
+ unsigned short ip;
+ unsigned short cs;
+ unsigned short sp;
+ unsigned short ss;
+ } x;
+ struct {
+ unsigned char edi[4];
+ unsigned char esi[4];
+ unsigned char ebp[4];
+ unsigned char res[4];
+ unsigned char bl, bh, ebx_b2, ebx_b3;
+ unsigned char dl, dh, edx_b2, edx_b3;
+ unsigned char cl, ch, ecx_b2, ecx_b3;
+ unsigned char al, ah, eax_b2, eax_b3;
+ } h;
+} RM_REGS;
+
+
+
+/* our API extensions use 32 bit magic numbers */
+#define FAF_ID(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d)
+
+
+
+/* ID code and magic return value for initialising the extensions */
+#define FAFEXT_INIT FAF_ID('I','N','I','T')
+#define FAFEXT_MAGIC FAF_ID('E','X', 0, 0)
+#define FAFEXT_MAGIC1 FAF_ID('E','X','0','1')
+
+
+
+/* extension providing a hardware-specific way to access video memory */
+#define FAFEXT_HWPTR FAF_ID('H','P','T','R')
+
+
+#if (defined __i386__) && (!defined NO_HWPTR)
+
+
+/* use seg+offset far pointers on i386 */
+typedef struct FAF_HWPTR
+{
+ int sel;
+ unsigned long offset;
+} FAF_HWPTR;
+
+#include
+#include
+
+#define hwptr_init(ptr, addr) \
+ if ((addr) && (!(ptr).sel)) { \
+ (ptr).sel = _my_ds(); \
+ (ptr).offset = (unsigned long)(addr); \
+ }
+
+#define hwptr_pokeb(ptr, off, val) _farpokeb((ptr).sel, (ptr).offset+(off), (val))
+#define hwptr_pokew(ptr, off, val) _farpokew((ptr).sel, (ptr).offset+(off), (val))
+#define hwptr_pokel(ptr, off, val) _farpokel((ptr).sel, (ptr).offset+(off), (val))
+
+#define hwptr_peekb(ptr, off) _farpeekb((ptr).sel, (ptr).offset+(off))
+#define hwptr_peekw(ptr, off) _farpeekw((ptr).sel, (ptr).offset+(off))
+#define hwptr_peekl(ptr, off) _farpeekl((ptr).sel, (ptr).offset+(off))
+
+#define hwptr_select(ptr) _farsetsel((ptr).sel)
+#define hwptr_unselect(ptr) (ptr).sel = _fargetsel()
+
+#define hwptr_nspokeb(ptr, off, val) _farnspokeb((ptr).offset+(off), (val))
+#define hwptr_nspokew(ptr, off, val) _farnspokew((ptr).offset+(off), (val))
+#define hwptr_nspokel(ptr, off, val) _farnspokel((ptr).offset+(off), (val))
+
+#define hwptr_nspeekb(ptr, off) _farnspeekb((ptr).offset+(off))
+#define hwptr_nspeekw(ptr, off) _farnspeekw((ptr).offset+(off))
+#define hwptr_nspeekl(ptr, off) _farnspeekl((ptr).offset+(off))
+
+
+#else
+
+
+/* use regular C pointers on other platforms or if hwptr is disabled */
+typedef void *FAF_HWPTR;
+
+#define hwptr_init(ptr, addr) ptr = (FAF_HWPTR)(addr)
+
+#define hwptr_pokeb(ptr, off, val) *((volatile unsigned char *)((ptr)+(off))) = (val)
+#define hwptr_pokew(ptr, off, val) *((volatile unsigned short *)((ptr)+(off))) = (val)
+#define hwptr_pokel(ptr, off, val) *((volatile unsigned long *)((ptr)+(off))) = (val)
+
+#define hwptr_peekb(ptr, off) (*((volatile unsigned char *)((ptr)+(off))))
+#define hwptr_peekw(ptr, off) (*((volatile unsigned short *)((ptr)+(off))))
+#define hwptr_peekl(ptr, off) (*((volatile unsigned long *)((ptr)+(off))))
+
+#define hwptr_select(ptr)
+#define hwptr_unselect(ptr) (ptr) = NULL
+
+#define hwptr_nspokeb(ptr, off, val) *((volatile unsigned char *)((ptr)+(off))) = (val)
+#define hwptr_nspokew(ptr, off, val) *((volatile unsigned short *)((ptr)+(off))) = (val)
+#define hwptr_nspokel(ptr, off, val) *((volatile unsigned long *)((ptr)+(off))) = (val)
+
+#define hwptr_nspeekb(ptr, off) (*((volatile unsigned char *)((ptr)+(off))))
+#define hwptr_nspeekw(ptr, off) (*((volatile unsigned short *)((ptr)+(off))))
+#define hwptr_nspeekl(ptr, off) (*((volatile unsigned long *)((ptr)+(off))))
+
+
+#endif /* hwptr structure definitions */
+
+
+/* interface structure containing hardware pointer data */
+typedef struct FAF_HWPTR_DATA
+{
+ FAF_HWPTR IOMemMaps[4];
+ FAF_HWPTR BankedMem;
+ FAF_HWPTR LinearMem;
+} FAF_HWPTR_DATA;
+
+
+
+/* extension providing a way for the config program to set driver variables */
+#define FAFEXT_CONFIG FAF_ID('C','O','N','F')
+
+
+
+/* config variable, so the install program can communicate with the driver */
+typedef struct FAF_CONFIG_DATA
+{
+ unsigned long id;
+ unsigned long value;
+} FAF_CONFIG_DATA;
+
+
+
+/* config variable ID used to enable/disable specific hardware functions */
+#define FAF_CFG_FEATURES FAF_ID('F','E','A','T')
+
+
+
+/* bitfield values for the FAF_CFG_FEATURES variable */
+#define fafLinear 0x00000001
+#define fafBanked 0x00000002
+#define fafHWCursor 0x00000004
+#define fafDrawScan 0x00000008
+#define fafDrawPattScan 0x00000010
+#define fafDrawColorPattScan 0x00000020
+#define fafDrawScanList 0x00000040
+#define fafDrawPattScanList 0x00000080
+#define fafDrawColorPattScanList 0x00000100
+#define fafDrawRect 0x00000200
+#define fafDrawPattRect 0x00000400
+#define fafDrawColorPattRect 0x00000800
+#define fafDrawLine 0x00001000
+#define fafDrawStippleLine 0x00002000
+#define fafDrawTrap 0x00004000
+#define fafDrawTri 0x00008000
+#define fafDrawQuad 0x00010000
+#define fafPutMonoImage 0x00020000
+#define fafPutMonoImageLin 0x00040000
+#define fafPutMonoImageBM 0x00080000
+#define fafBitBlt 0x00100000
+#define fafBitBltSys 0x00200000
+#define fafBitBltLin 0x00400000
+#define fafBitBltBM 0x00800000
+#define fafSrcTransBlt 0x01000000
+#define fafSrcTransBltSys 0x02000000
+#define fafSrcTransBltLin 0x04000000
+#define fafSrcTransBltBM 0x08000000
+
+
+
+/* helper function for enabling/disabling driver routines */
+void fixup_feature_list(AF_DRIVER *af, unsigned long flags);
+
+
+
+/* extension providing libc exports (needed for Nucleus compatibility) */
+#define FAFEXT_LIBC FAF_ID('L','I','B','C')
+
+
+typedef struct FAF_LIBC_DATA
+{
+ long size;
+ void (*abort)();
+ void *(*calloc)(unsigned long num_elements, unsigned long size);
+ void (*exit)(int status);
+ void (*free)(void *ptr);
+ char *(*getenv)(const char *name);
+ void *(*malloc)(unsigned long size);
+ void *(*realloc)(void *ptr, unsigned long size);
+ int (*system)(const char *s);
+ int (*putenv)(const char *val);
+ int (*open)(const char *file, int mode, int permissions);
+ int (*access)(const char *filename, int flags);
+ int (*close)(int fd);
+ int (*lseek)(int fd, int offset, int whence);
+ int (*read)(int fd, void *buffer, unsigned long count);
+ int (*unlink)(const char *file);
+ int (*write)(int fd, const void *buffer, unsigned long count);
+ int (*isatty)(int fd);
+ int (*remove)(const char *file);
+ int (*rename)(const char *oldname, const char *newname);
+ unsigned int (*time)(unsigned int *t);
+ void (*setfileattr)(const char *filename, unsigned attrib);
+ unsigned long (*getcurrentdate)();
+} FAF_LIBC_DATA;
+
+
+
+/* extension providing pmode exports (needed for Nucleus compatibility) */
+#define FAFEXT_PMODE FAF_ID('P','M','O','D')
+
+
+
+/* It has to be said, having this many exported functions is truly insane.
+ * How on earth can SciTech need this much crap just to write a simple
+ * video driver? Unfortunately we have to include it all in order to
+ * support their Nucleus drivers...
+ */
+
+typedef union
+{
+ struct {
+ unsigned long eax, ebx, ecx, edx, esi, edi, cflag;
+ } e;
+ struct {
+ unsigned short ax, ax_hi;
+ unsigned short bx, bx_hi;
+ unsigned short cx, cx_hi;
+ unsigned short dx, dx_hi;
+ unsigned short si, si_hi;
+ unsigned short di, di_hi;
+ unsigned short cflag, cflag_hi;
+ } x;
+ struct {
+ unsigned char al, ah; unsigned short ax_hi;
+ unsigned char bl, bh; unsigned short bx_hi;
+ unsigned char cl, ch; unsigned short cx_hi;
+ unsigned char dl, dh; unsigned short dx_hi;
+ } h;
+} SILLY_SCITECH_REGS;
+
+
+
+typedef struct
+{
+ unsigned short es, cs, ss, ds, fs, gs;
+} SILLY_SCITECH_SREGS;
+
+
+
+typedef struct FAF_PMODE_DATA
+{
+ long size;
+ int (*getModeType)();
+ void *(*getBIOSPointer)();
+ void *(*getA0000Pointer)();
+ void *(*mapPhysicalAddr)(unsigned long base, unsigned long limit);
+ void *(*mallocShared)(long size);
+ int (*mapShared)(void *ptr);
+ void (*freeShared)(void *ptr);
+ void *(*mapToProcess)(void *linear, unsigned long limit);
+ void (*loadDS)();
+ void (*saveDS)();
+ void *(*mapRealPointer)(unsigned int r_seg, unsigned int r_off);
+ void *(*allocRealSeg)(unsigned int size, unsigned int *r_seg, unsigned int *r_off);
+ void (*freeRealSeg)(void *mem);
+ void *(*allocLockedMem)(unsigned int size, unsigned long *physAddr);
+ void (*freeLockedMem)(void *p);
+ void (*callRealMode)(unsigned int seg, unsigned int off, SILLY_SCITECH_REGS *regs, SILLY_SCITECH_SREGS *sregs);
+ int (*int86)(int intno, SILLY_SCITECH_REGS *in, SILLY_SCITECH_REGS *out);
+ int (*int86x)(int intno, SILLY_SCITECH_REGS *in, SILLY_SCITECH_REGS *out, SILLY_SCITECH_SREGS *sregs);
+ void (*DPMI_int86)(int intno, RM_REGS *regs);
+ void (*segread)(SILLY_SCITECH_SREGS *sregs);
+ int (*int386)(int intno, SILLY_SCITECH_REGS *in, SILLY_SCITECH_REGS *out);
+ int (*int386x)(int intno, SILLY_SCITECH_REGS *in, SILLY_SCITECH_REGS *out, SILLY_SCITECH_SREGS *sregs);
+ void (*availableMemory)(unsigned long *physical, unsigned long *total);
+ void *(*getVESABuf)(unsigned int *len, unsigned int *rseg, unsigned int *roff);
+ long (*getOSType)();
+ void (*fatalError)(const char *msg);
+ void (*setBankA)(int bank);
+ void (*setBankAB)(int bank);
+ const char *(*getCurrentPath)();
+ const char *(*getVBEAFPath)();
+ const char *(*getNucleusPath)();
+ const char *(*getNucleusConfigPath)();
+ const char *(*getUniqueID)();
+ const char *(*getMachineName)();
+ int (*VF_available)();
+ void *(*VF_init)(unsigned long baseAddr, int bankSize, int codeLen, void *bankFunc);
+ void (*VF_exit)();
+ int (*kbhit)();
+ int (*getch)();
+ int (*openConsole)();
+ int (*getConsoleStateSize)();
+ void (*saveConsoleState)(void *stateBuf, int console_id);
+ void (*restoreConsoleState)(const void *stateBuf, int console_id);
+ void (*closeConsole)(int console_id);
+ void (*setOSCursorLocation)(int x, int y);
+ void (*setOSScreenWidth)(int width, int height);
+ int (*enableWriteCombine)(unsigned long base, unsigned long length);
+ void (*backslash)(char *filename);
+} FAF_PMODE_DATA;
+
+
+
+/* assorted helper functions */
+void trace_putc(char c);
+void trace_printf(char *msg, ...);
+
+void rm_int(int num, RM_REGS *regs);
+
+int allocate_dos_memory(int size, int *sel);
+void free_dos_memory(int sel);
+
+int allocate_selector(int addr, int size);
+void free_selector(int sel);
+
+int get_vesa_info(int *vram_size, unsigned long *linear_addr, void (*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));
+
+
+
+/* read_vga_register:
+ * Reads the contents of a VGA hardware register.
+ */
+extern inline int read_vga_register(int port, int index)
+{
+ if (port==0x3C0)
+ inportb(0x3DA);
+
+ outportb(port, index);
+ return inportb(port+1);
+}
+
+
+
+/* write_vga_register:
+ * Writes a byte to a VGA hardware register.
+ */
+extern inline void write_vga_register(int port, int index, int v)
+{
+ if (port==0x3C0) {
+ inportb(0x3DA);
+ outportb(port, index);
+ outportb(port, v);
+ }
+ else {
+ outportb(port, index);
+ outportb(port+1, v);
+ }
+}
+
+
+
+/* alter_vga_register:
+ * Alters specific bits of a VGA hardware register.
+ */
+extern inline void alter_vga_register(int port, int index, int mask, int v)
+{
+ int temp;
+ temp = read_vga_register(port, index);
+ temp &= (~mask);
+ temp |= (v & mask);
+ write_vga_register(port, index, temp);
+}
+
+
+
+/* test_vga_register:
+ * Tests whether specific bits of a VGA hardware register can be changed.
+ */
+extern inline int test_vga_register(int port, int index, int mask)
+{
+ int old, nw1, nw2;
+
+ old = read_vga_register(port, index);
+ write_vga_register(port, index, old & (~mask));
+ nw1 = read_vga_register(port, index) & mask;
+ write_vga_register(port, index, old | mask);
+ nw2 = read_vga_register(port, index) & mask;
+ write_vga_register(port, index, old);
+
+ return ((nw1==0) && (nw2==mask));
+}
+
+
+
+/* test_register:
+ * Tests whether specific bits of a hardware register can be changed.
+ */
+extern inline int test_register(int port, int mask)
+{
+ int old, nw1, nw2;
+
+ old = inportb(port);
+ outportb(port, old & (~mask));
+ nw1 = inportb(port) & mask;
+ outportb(port, old | mask);
+ nw2 = inportb(port) & mask;
+ outportb(port, old);
+
+ return ((nw1==0) && (nw2==mask));
+}
+
+
+
+/* PCI routines added by SET */
+#define PCIConfigurationAddress 0xCF8
+#define PCIConfigurationData 0xCFC
+#define PCIEnable 0x80000000
+
+extern int FindPCIDevice(int deviceID, int vendorID, int deviceIndex, int *handle);
+
+extern inline unsigned PCIReadLong(int handle, int index)
+{
+ outportl(PCIConfigurationAddress, PCIEnable | handle | index);
+ return inportl(PCIConfigurationData);
+}
diff --git a/video7/driver.c b/video7/driver.c
new file mode 100644
index 0000000..7e6abd6
--- /dev/null
+++ b/video7/driver.c
@@ -0,0 +1,571 @@
+/*
+ * ______ ____ ______ _____ ______
+ * | ____| | _ \| ____| / / _ \| ____|
+ * | |__ _ __ ___ ___| |_) | |__ / / |_| | |__
+ * | __| '__/ _ \/ _ \ _ <| __| / /| _ | __|
+ * | | | | | __/ __/ |_) | |____ / / | | | | |
+ * |_| |_| \___|\___|____/|______/_/ |_| |_|_|
+ *
+ *
+ * Video-7 driver (based on the Allegro Video-7 code).
+ *
+ * By Peter Monks, Markus Oberhumer, and 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);
+
+
+
+/* list which ports we are going to access (only needed under Linux) */
+unsigned short ports_table[] = { 0xFFFF };
+
+
+
+/* internal driver state variables */
+int af_bpp;
+int af_width;
+int af_height;
+int af_visible_page;
+int af_active_page;
+int af_scroll_x;
+int af_scroll_y;
+int af_bank;
+
+
+
+/* FreeBE/AF extension allowing farptr access to video memory */
+FAF_HWPTR_DATA hwptr;
+
+
+
+/* list of available video modes */
+typedef struct VIDEO_MODE
+{
+ int w, h;
+ int bpp;
+ int num;
+} VIDEO_MODE;
+
+
+VIDEO_MODE mode_list[] =
+{
+ { 640, 400, 8, 0x66 },
+ { 640, 480, 8, 0x67 },
+ { 720, 540, 8, 0x68 },
+ { 800, 600, 8, 0x69 },
+ { 1024, 768, 8, 0x6A }
+};
+
+
+#define NUM_MODES (int)(sizeof(mode_list)/sizeof(VIDEO_MODE))
+
+
+short available_modes[NUM_MODES+1] = { 1, 2, 3, 4, 5, -1 };
+
+
+
+/* detect:
+ * Detects the presence of a Video-7 card.
+ */
+char *detect(unsigned long *vidmem)
+{
+ RM_REGS r;
+ unsigned v;
+ int old;
+
+ old = read_vga_register(0x3C4, 6);
+ write_vga_register(0x3C4, 6, 0xEA); /* enable BIOS extensions */
+
+ r.x.ax = 0x6F00; /* installation check */
+ r.x.bx = 0x0000;
+ rm_int(0x10, &r);
+ if ((r.x.bx != 0x5637) && (r.x.bx != 0x4850)) {
+ write_vga_register(0x3C4, 6, old);
+ return NULL;
+ }
+
+ r.x.ax = 0x6F07; /* get configuration */
+ rm_int(0x10, &r);
+ if (r.h.al != 0x6F) {
+ write_vga_register(0x3C4, 6, old);
+ return NULL;
+ }
+
+ *vidmem = (r.h.ah & 0x7F) * 256;
+
+ v = (read_vga_register(0x3C4, 0x8F)<<8) + read_vga_register(0x3C4, 0x8E);
+
+ switch (v) {
+ case 0x7140 ...
+ 0x714F: return "V7 208A";
+ case 0x7151: return "V7 208B";
+ case 0x7152: return "V7 208CD";
+ case 0x7760: return "V7 216BC";
+ case 0x7763: return "V7 216D";
+ case 0x7764: return "V7 216E";
+ case 0x7765: return "V7 216F";
+
+ default:
+ return NULL;
+ }
+}
+
+
+
+/* SetupDriver:
+ * Fills in our driver header block.
+ */
+int SetupDriver(AF_DRIVER *af)
+{
+ char *name;
+ int i;
+
+ name = detect(&af->TotalMemory);
+
+ if (!name)
+ return 1;
+
+ i = 0;
+ while (af->OemVendorName[i])
+ i++;
+
+ af->OemVendorName[i++] = ',';
+ af->OemVendorName[i++] = ' ';
+
+ while (*name)
+ af->OemVendorName[i++] = *(name++);
+
+ af->OemVendorName[i] = 0;
+
+ af->AvailableModes = available_modes;
+
+ af->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ af->BankSize = 64;
+ af->BankedBasePtr = 0xA0000;
+
+ af->IOPortsTable = ports_table;
+
+ 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;
+
+ 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.
+ */
+int InitDriver(AF_DRIVER *af)
+{
+ 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
+
+ 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];
+
+ for (i=0; i<(int)sizeof(AF_MODE_INFO); i++)
+ ((char *)modeInfo)[i] = 0;
+
+ modeInfo->Attributes = (afHaveMultiBuffer |
+ afHaveVirtualScroll |
+ afHaveBankedBuffer);
+
+ modeInfo->XResolution = info->w;
+ modeInfo->YResolution = info->h;
+ modeInfo->BitsPerPixel = info->bpp;
+
+ modeInfo->MaxBuffers = (af->TotalMemory*1024) /
+ (info->w*info->h*BYTES_PER_PIXEL(info->bpp));
+
+ if (info->w > 1024) {
+ modeInfo->MaxBytesPerScanLine = 2048*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 2048;
+ }
+ else {
+ modeInfo->MaxBytesPerScanLine = 1024*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->MaxScanLineWidth = 1024;
+ }
+
+ modeInfo->BytesPerScanLine = info->w*BYTES_PER_PIXEL(info->bpp);
+ modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
+
+ modeInfo->MaxPixelClock = 135000000;
+
+ return 0;
+}
+
+
+
+/* SetVideoMode:
+ * Sets the specified video mode, returning zero on success.
+ */
+long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
+{
+ long available_vram;
+ long used_vram;
+ int width;
+ VIDEO_MODE *info;
+ RM_REGS r;
+
+ /* reject anything with hardware stereo, linear framebuffer, or noclear */
+ if (mode & 0xC400)
+ return -1;
+
+ mode &= 0x3FF;
+
+ if ((mode <= 0) || (mode > NUM_MODES))
+ return -1;
+
+ info = &mode_list[mode-1];
+
+ /* call BIOS to set the mode */
+ r.x.ax = 0x6F05;
+ r.x.bx = info->num;
+ rm_int(0x10, &r);
+
+ /* adjust the virtual width for widescreen modes */
+ if (virtualX > info->w) {
+ if (virtualX > 1024)
+ return -1;
+
+ *bytesPerLine = ((virtualX*BYTES_PER_PIXEL(info->bpp))+15)&0xFFF0;
+
+ width = read_vga_register(0x3D4, 0x13);
+ write_vga_register(0x3D4, 0x13, (width * (*bytesPerLine)) / (info->w*BYTES_PER_PIXEL(info->bpp)));
+ }
+ else
+ *bytesPerLine = info->w*BYTES_PER_PIXEL(info->bpp);
+
+ /* tweak some hardware registers */
+ write_vga_register(0x3C4, 6, 0xEA); /* enable BIOS extensions */
+ alter_vga_register(0x3C4, 0xE0, 0x80, 0); /* disable split banks */
+ alter_vga_register(0x3C4, 0xF6, 0xC0, 0xC0); /* disable wrap-around */
+ alter_vga_register(0x3C4, 0xFC, 0x07, 4); /* set compatibility control */
+
+ /* store info about the current mode */
+ af_bpp = info->bpp;
+ af_width = *bytesPerLine;
+ af_height = MAX(info->h, virtualY);
+ af_visible_page = 0;
+ af_active_page = 0;
+ af_scroll_x = 0;
+ af_scroll_y = 0;
+ af_bank = -1;
+
+ af->BufferEndX = af_width/BYTES_PER_PIXEL(af_bpp)-1;
+ af->BufferEndY = af_height-1;
+ af->OriginOffset = 0;
+
+ used_vram = af_width * af_height * numBuffers;
+ available_vram = af->TotalMemory*1024 ;
+
+ if (used_vram > available_vram)
+ return -1;
+
+ if (available_vram-used_vram >= af_width) {
+ af->OffscreenOffset = used_vram;
+ af->OffscreenStartY = af_height*numBuffers;
+ af->OffscreenEndY = available_vram/af_width-1;
+ }
+ else {
+ af->OffscreenOffset = 0;
+ af->OffscreenStartY = 0;
+ af->OffscreenEndY = 0;
+ }
+
+ 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. The waitVRT value may be one of:
+ *
+ * -1 = don't set hardware, just store values for next page flip to use
+ * 0 = set values and return immediately
+ * 1 = set values and wait for retrace
+ */
+void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
+{
+ if (waitVRT >= 0) {
+ long a = (x * BYTES_PER_PIXEL(af_bpp)) + ((y + af_visible_page*af_height) * af_width);
+
+ asm volatile ("cli");
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 1);
+ }
+
+ /* write high bits to Video7 registers */
+ alter_vga_register(0x3C4, 0xF6, 0x30, a>>(18-4));
+
+ /* write to normal VGA address registers */
+ write_vga_register(0x3D4, 0x0D, (a>>2) & 0xFF);
+ write_vga_register(0x3D4, 0x0C, (a>>10) & 0xFF);
+
+ asm volatile ("sti");
+
+ if (waitVRT) {
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ /* write low 2 bits to VGA horizontal pan register */
+ write_vga_register(0x3C0, 0x33, a&3);
+ }
+
+ 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->OriginOffset = af_width*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;
+
+ if (waitVRT) {
+ do {
+ } while (inportb(0x3DA) & 8);
+
+ do {
+ } while (!(inportb(0x3DA) & 8));
+ }
+
+ for (i=0; i freebe\freebe.mft
+echo freebe/freebe.mft >> freebe\freebe.mft
+zip -9 freebe\freebe_s.zip freebe\freebe.mft
+cd freebe
+make.exe install.exe
+zip -9 freebe_b.zip install.exe readme.txt