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/28800Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
ATI mach64Uses BIOSBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
Avance Logic ALG-2101, ALG-2201, ALG-2228, ALG-2301, ALG-2302Uses BIOSBanked modes onlyNo FreeBE/AF extensionsDumb framebuffer
Cirrus 54xx (not 546x). Should be ok with 5426, 5428, 7541, 7543Uses BIOSBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
Matrox Millenium, Mystique, Millenium IIUses BIOSBanked and linear modesSupports farptr and config extensionsHardware accelerated
NVidia Riva 128, TNT. Conflicts with Windows!100% portableBanked and linear modesSupports config extensionHardware accelerated
ParadiseUses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
S3Uses BIOSBanked modes onlySupports farptr extensionHardware accelerated
Trident TGUI 9440. Doesn't work under Windows!100% portableBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
TridentUses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
Tseng ET3000/ET4000/ET6000Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
Video-7Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
stub driver (for testing and development purposes only)Uses BIOSBanked and linear modesSupports farptr and config extensionsSlow 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." +

+

+
+
+

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/28800Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
ATI mach64Uses BIOSBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
Avance Logic ALG-2101, ALG-2201, ALG-2228, ALG-2301, ALG-2302Uses BIOSBanked modes onlyNo FreeBE/AF extensionsDumb framebuffer
Cirrus 54xx (not 546x). Should be ok with 5426, 5428, 7541, 7543Uses BIOSBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
Matrox Millenium, Mystique, Millenium IIUses BIOSBanked and linear modesSupports farptr and config extensionsHardware accelerated
NVidia Riva 128, TNT. Conflicts with Windows!100% portableBanked and linear modesSupports config extensionHardware accelerated
ParadiseUses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
S3Uses BIOSBanked modes onlySupports farptr extensionHardware accelerated
Trident TGUI 9440. Doesn't work under Windows!100% portableBanked and linear modesNo FreeBE/AF extensionsHardware accelerated
TridentUses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
Tseng ET3000/ET4000/ET6000Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
Video-7Uses BIOSBanked modes onlySupports farptr extensionDumb framebuffer
stub driver (for testing and development purposes only)Uses BIOSBanked and linear modesSupports farptr and config extensionsSlow 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/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 visible name +# ~2 is the name of the node +# +Entry="
  • ~1" +End="
  • " + +# +# ~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 of functions +
  • List by files +
  • + + + +


    + +

    Alphabetical List

    + + +
  • BitBlt +
  • BitBltSys +
  • DisableDirectAccess +
  • DrawColorPattRect +
  • DrawColorPattScan +
  • DrawPattRect +
  • DrawPattScan +
  • DrawRect +
  • DrawScan +
  • DrawStippleLine +
  • DrawTrap +
  • DumpValues +
  • EnableDirectAccess +
  • ExtStub +
  • FindClosestVClk +
  • GetClosestPixelClock +
  • GetDisplayStartStatus +
  • GetVideoModeInfo +
  • InitDriver +
  • PutMonoImage +
  • ReadVSync +
  • RestoreTextMode +
  • Set8x8ColorPattern +
  • Set8x8MonoPattern +
  • SetActiveBuffer +
  • SetBank +
  • SetCursor +
  • SetCursorColor +
  • SetCursorPos +
  • SetDisplayStart +
  • SetLineStipple +
  • SetLineStippleCount +
  • SetPaletteData +
  • SetupDriver +
  • SetVideoMode +
  • SetVisibleBuffer +
  • SetVSync +
  • ShowCursor +
  • SrcTransBlt +
  • SrcTransBltSys +
  • TestMemory +
  • TGUI9440LoadRegs +
  • TGUI9440SaveRegs +
  • Use8x8ColorPattern +
  • VGALoadRegs +
  • VGASaveRegs +
  • WaitTillIdle +
  • + + + +


    + +

    Files

    + + +
  • driver.c +
  • dumpreg.c +
  • rw_regs.c +
  • + + +


    + +

    driver.c

    + + + + +
  • BitBlt +
  • BitBltSys +
  • DisableDirectAccess +
  • DrawColorPattRect +
  • DrawColorPattScan +
  • DrawPattRect +
  • DrawPattScan +
  • DrawRect +
  • DrawScan +
  • DrawStippleLine +
  • DrawTrap +
  • EnableDirectAccess +
  • ExtStub +
  • FindClosestVClk +
  • GetClosestPixelClock +
  • GetDisplayStartStatus +
  • GetVideoModeInfo +
  • InitDriver +
  • PutMonoImage +
  • RestoreTextMode +
  • Set8x8ColorPattern +
  • Set8x8MonoPattern +
  • SetActiveBuffer +
  • SetBank +
  • SetCursor +
  • SetCursorColor +
  • SetCursorPos +
  • SetDisplayStart +
  • SetLineStipple +
  • SetLineStippleCount +
  • SetPaletteData +
  • SetupDriver +
  • SetVideoMode +
  • SetVisibleBuffer +
  • ShowCursor +
  • SrcTransBlt +
  • SrcTransBltSys +
  • TestMemory +
  • Use8x8ColorPattern +
  • WaitTillIdle +
  • + + + +


    + +

    dumpreg.c

    + + + + +
  • DumpValues +
  • + + + +


    + +

    rw_regs.c

    + + + + +
  • ReadVSync +
  • SetVSync +
  • TGUI9440LoadRegs +
  • TGUI9440SaveRegs +
  • VGALoadRegs +
  • VGASaveRegs +
  • + + + + + +


    + +
    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