/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Video driver for VGA mode 13h (320x200x256). * * By Shawn Hargreaves. * * 320x100 mode contributed by Salvador Eduardo Tropea. * * 80x80 mode contributed by Pedro Cardoso. * * See readme.txt for copyright information. */ #include #include "allegro.h" #ifdef GFX_HAS_VGA #include "allegro/internal/aintern.h" #include "allegro/internal/aintvga.h" #ifdef ALLEGRO_INTERNAL_HEADER #include ALLEGRO_INTERNAL_HEADER #endif #if (!defined ALLEGRO_LINUX) || ((defined ALLEGRO_LINUX_VGA) && ((!defined ALLEGRO_WITH_MODULES) || (defined ALLEGRO_MODULE))) static BITMAP *vga_init(int w, int h, int v_w, int v_h, int color_depth); static void vga_exit(BITMAP *b); static int vga_scroll(int x, int y); static GFX_MODE_LIST *vga_fetch_mode_list(void); GFX_DRIVER gfx_vga = { GFX_VGA, empty_string, empty_string, "Standard VGA", vga_init, vga_exit, NULL, _vga_vsync, _vga_set_palette_range, NULL, NULL, NULL, /* no triple buffering */ NULL, NULL, NULL, NULL, /* no video bitmaps */ NULL, NULL, /* no system bitmaps */ NULL, NULL, NULL, NULL, /* no hardware cursor */ NULL, /* no drawing mode hook */ _save_vga_mode, _restore_vga_mode, NULL, /* AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a)); */ vga_fetch_mode_list, 320, 200, TRUE, 0, 0, 0x10000, 0, FALSE }; static GFX_MODE vga_gfx_modes[] = { { 80, 80, 8 }, { 160, 120, 8 }, { 256, 256, 8 }, { 320, 100, 8 }, { 320, 200, 8 }, { 0, 0, 0 } }; /* vga_init: * Selects mode 13h and creates a screen bitmap for it. */ static BITMAP *vga_init(int w, int h, int v_w, int v_h, int color_depth) { unsigned long addr; BITMAP *b; int c; /* check it is a valid resolution */ if (color_depth != 8) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VGA only supports 8 bit color")); return NULL; } /* for setting GFX_SAFE */ if ((!w) && (!h)) { w = 320; h = 200; } if ((w == 320) && (h == 200) && (v_w <= 320) && (v_h <= 200)) { /* standard mode 13h */ addr = _set_vga_mode(0x13); if (!addr) return NULL; b = _make_bitmap(320, 200, addr, &gfx_vga, 8, 320); if (!b) return NULL; gfx_vga.scroll = NULL; gfx_vga.w = 320; gfx_vga.h = 200; } else if ((w == 320) && (h == 100) && (v_w <= 320) && (v_h <= 200)) { /* tweaked 320x100 mode */ addr = _set_vga_mode(0x13); if (!addr) return NULL; b = _make_bitmap(320, 200, addr, &gfx_vga, 8, 320); if (!b) return NULL; outportb(0x3D4, 9); outportb(0x3D5, inportb(0x3D5) | 0x80); gfx_vga.scroll = vga_scroll; gfx_vga.w = 320; gfx_vga.h = 100; } else if ((w == 256) && (h == 256) && (v_w <= 256) && (v_h <= 256)) { /* tweaked 256x256 mode */ addr = _set_vga_mode(0x13); if (!addr) return NULL; b = _make_bitmap(256, 256, addr, &gfx_vga, 8, 256); if (!b) return NULL; outportb(0x3D4, 0x11); c = inportb(0x3D5) & 0x7F; outportb(0x3D4, (c << 8) | 0x11); outportb(0x3D5, c); outportb(0x3C2, 0xE3); outportw(0x3D4, 0x5F00); outportw(0x3D4, 0x3F01); outportw(0x3D4, 0x4002); outportw(0x3D4, 0x8203); outportw(0x3D4, 0x4A04); outportw(0x3D4, 0x9A05); outportw(0x3D4, 0x2306); outportw(0x3D4, 0xB207); outportw(0x3D4, 0x0008); outportw(0x3D4, 0x6109); outportw(0x3D4, 0x0A10); outportw(0x3D4, 0xAC11); outportw(0x3D4, 0xFF12); outportw(0x3D4, 0x2013); outportw(0x3D4, 0x4014); outportw(0x3D4, 0x0715); outportw(0x3D4, 0x1A16); outportw(0x3D4, 0xA317); outportw(0x3C4, 0x0101); outportw(0x3C4, 0x0E04); outportw(0x3CE, 0x4005); outportw(0x3CE, 0x0506); inportb(0x3DA); outportb(0x3C0, 0x30); outportb(0x3C0, 0x41); inportb(0x3DA); outportb(0x3C0, 0x33); outportb(0x3C0, 0x00); outportb(0x3C6, 0xFF); gfx_vga.scroll = NULL; gfx_vga.w = 256; gfx_vga.h = 256; } else if ((w == 160) && (h == 120) && (v_w <= 160) && (v_h <= 409)) { /* tweaked 160x120 mode */ addr = _set_vga_mode(0x0D); if (!addr) return NULL; b = _make_bitmap(160, 409, addr, &gfx_vga, 8, 160); if (!b) return NULL; outportb(0x3D4, 0x11); outportb(0x3D5, inportb(0x3D5)&0x7F); outportb(0x3D4, 0x04); outportb(0x3D5, inportb(0x3D5)+1); outportb(0x3D4, 0x11); outportb(0x3D5, inportb(0x3D5)|0x80); outportb(0x3C2, (inportb(0x3CC)&~0xC0)|0x80); outportb(0x3D4, 0x11); outportb(0x3D5, inportb(0x3D5)&0x7F); outportb(0x3D4, 0x06); outportb(0x3D5, 0x0B); outportb(0x3D4, 0x07); outportb(0x3D5, 0x3E); outportb(0x3D4, 0x10); outportb(0x3D5, 0xEA); outportb(0x3D4, 0x11); outportb(0x3D5, 0x8C); outportb(0x3D4, 0x12); outportb(0x3D5, 0xDF); outportb(0x3D4, 0x15); outportb(0x3D5, 0xE7); outportb(0x3D4, 0x16); outportb(0x3D5, 0x04); outportb(0x3D4, 0x11); outportb(0x3D5, inportb(0x3D5)|0x80); outportb(0x3CE, 0x05); outportb(0x3CF, (inportb(0x3CF)&0x60)|0x40); inportb(0x3DA); outportb(0x3C0, 0x30); outportb(0x3C0, inportb(0x3C1)|0x40); for (c=0; c<16; c++) { outportb(0x3C0, c); outportb(0x3C0, c); } outportb(0x3C0, 0x20); outportb(0x3C8, 0x00); outportb(0x3C4, 0x04); outportb(0x3C5, (inportb(0x3C5)&0xF7)|8); outportb(0x3D4, 0x14); outportb(0x3D5, (inportb(0x3D5)&~0x40)|64); outportb(0x3D4, 0x017); outportb(0x3D5, (inportb(0x3D5)&~0x40)|64); outportb(0x3D4, 0x09); outportb(0x3D5, (inportb(0x3D5)&0x60)|3); gfx_vga.scroll = vga_scroll; gfx_vga.w = 160; gfx_vga.h = 120; } else if ((w == 80) && (h == 80) && (v_w <= 80) && (v_h <= 819)) { /* tweaked 80x80 mode */ addr = _set_vga_mode(0x13); if (!addr) return NULL; b = _make_bitmap(80, 819, addr, &gfx_vga, 8, 80); if (!b) return NULL; outportw(0x3C4, 0x0604); outportw(0x3C4, 0x0F02); outportw(0x3D4, 0x0014); outportw(0x3D4, 0xE317); outportw(0x3D4, 0xE317); outportw(0x3D4, 0x0409); gfx_vga.scroll = vga_scroll; gfx_vga.w = 80; gfx_vga.h = 80; } else { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not a valid VGA resolution")); return NULL; } #ifdef ALLEGRO_LINUX b->vtable->acquire = __al_linux_acquire_bitmap; b->vtable->release = __al_linux_release_bitmap; #endif return b; } /* vga_exit: * Unsets the video mode. */ static void vga_exit(BITMAP *b) { _unset_vga_mode(); } /* vga_scroll: * Hardware scrolling routine for standard VGA modes. */ static int vga_scroll(int x, int y) { long a = (x + (y * VIRTUAL_W)); if (gfx_vga.w > 80) a /= 4; DISABLE(); if (_wait_for_vsync) _vsync_out_h(); /* write to VGA address registers */ _write_vga_register(_crtc, 0x0D, a & 0xFF); _write_vga_register(_crtc, 0x0C, (a>>8) & 0xFF); ENABLE(); if (_wait_for_vsync) _vsync_in(); return 0; } /* vga_fetch_mode_list: * Creates a list of of currently implemented VGA modes. */ static GFX_MODE_LIST *vga_fetch_mode_list(void) { GFX_MODE_LIST *mode_list; mode_list = malloc(sizeof(GFX_MODE_LIST)); if (!mode_list) return NULL; mode_list->mode = malloc(sizeof(vga_gfx_modes)); if (!mode_list->mode) return NULL; memcpy(mode_list->mode, vga_gfx_modes, sizeof(vga_gfx_modes)); mode_list->num_modes = sizeof(vga_gfx_modes) / sizeof(GFX_MODE) - 1; return mode_list; } #ifdef ALLEGRO_MODULE extern void _module_init_modex(int); /* from modex.c */ /* _module_init: * Called when loaded as a dynamically linked module. */ void _module_init(int system_driver) { _module_init_modex(system_driver); if (system_driver == SYSTEM_LINUX) _unix_register_gfx_driver(GFX_VGA, &gfx_vga, TRUE, TRUE); } #endif /* ifdef ALLEGRO_MODULE */ #endif /* (!defined ALLEGRO_LINUX) || ((defined ALLEGRO_LINUX_VGA) && ...) */ #endif /* ifdef GFX_HAS_VGA */