/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * VGA helper functions for Linux Allegro. * * Originally by Marek Habersack, mangled by George Foot. * * See readme.txt for copyright information. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "allegro.h" #ifdef ALLEGRO_LINUX_VGA #include "allegro/internal/aintern.h" #include "allegro/platform/aintunix.h" #include "allegro/internal/aintvga.h" #include "linalleg.h" #include #include #include #include #include #include #include #include /* Used by the text font routines, to access the video memory */ static struct MAPPED_MEMORY vram = { VGA_MEMORY_BASE, VGA_MEMORY_SIZE, PROT_READ | PROT_WRITE, NULL }; int __al_linux_init_vga_helpers (void) { __al_linux_map_memory (&vram); _vga_regs_init(); return 0; } int __al_linux_shutdown_vga_helpers (void) { __al_linux_unmap_memory (&vram); return 0; } /* __al_linux_set_vga_regs: * Write the standard VGA registers using values from the passed structure. */ void __al_linux_set_vga_regs(MODE_REGISTERS *regs) { int i = 0; if (!regs) return; outportb(MISC_REG_W, regs->misc); outportw(SEQ_REG_I, 0x0100); for (i = 1; i < N_SEQ_REGS; i++) outportw(SEQ_REG_I, (regs->seq[i] << 8) | i); outportw(SEQ_REG_I, 0x0300); outportw(_crtc, ((_read_vga_register(_crtc, 0x11) & 0x7F) << 8) | 0x11); for (i = 0; i < N_CRTC_REGS; i++) outportw(_crtc, (regs->crt[i] << 8) | i); for (i = 0; i < N_GC_REGS; i++) outportw(GC_REG_I, (regs->gc[i] << 8) | i); for (i = 0; i < N_ATC_REGS; i++) { inportb(_is1); outportb(ATC_REG_IW, i); outportb(ATC_REG_IW, regs->atc[i]); __just_a_moment(); } } /* __al_linux_get_vga_regs: * Read and save in the passed array all standard VGA regs for the current * video mode. */ void __al_linux_get_vga_regs(MODE_REGISTERS *regs) { int i = 0; if (!regs) return; regs->misc = inportb(MISC_REG_R); for (i = 0; i < N_CRTC_REGS; i++) { outportb(_crtc, i); regs->crt[i] = inportb(_crtc+1); } for (i = 0; i < N_GC_REGS; i++) { outportb(GC_REG_I, i); regs->gc[i] = inportb(GC_REG_RW); } for (i = 0; i < N_SEQ_REGS; i++) { outportb(SEQ_REG_I, i); regs->seq[i] = inportb(SEQ_REG_RW); } for (i = 0; i < N_ATC_REGS; i++) { inportb(_is1); outportb(ATC_REG_IW, i); regs->atc[i] = inportb(ATC_REG_R); __just_a_moment(); } } static void __al_linux_save_palette (MODE_REGISTERS *regs) { int c; unsigned char *ptr; ASSERT(regs); ptr = regs->palette.vga; for (c = 0; c < 256; c++) { outportb (0x3c7, c); *ptr++ = inportb (0x3c9); *ptr++ = inportb (0x3c9); *ptr++ = inportb (0x3c9); } } static void __al_linux_restore_palette (MODE_REGISTERS *regs) { int c; unsigned char *ptr; ASSERT(regs); ptr = regs->palette.vga; for (c = 0; c < 256; c++) { outportb (0x3c8, c); outportb (0x3c9, *ptr++); outportb (0x3c9, *ptr++); outportb (0x3c9, *ptr++); } } static inline void slow_byte_copy(char *from, char *to, unsigned count) { unsigned int i; ASSERT(from && to); for (i = 0; i < count; i++) { *to++ = *from++; outportb(0x80, 0x00); /* 1ms delay */ } } /* __al_linux_save_text_font: * Copy the text font data from the video memory. Since some cards won't work * properly unless we save/restore fonts from both 2nd and 3rd plane, we save * them both. */ static void __al_linux_save_text_font (MODE_REGISTERS *regs) { ASSERT(regs); if (!regs->text_font1) regs->text_font1 = (unsigned char*) malloc (VGA_FONT_SIZE); if (!regs->text_font2) regs->text_font2 = (unsigned char*) malloc (VGA_FONT_SIZE); /* First switch to a 4bpp video mode, so that we have selective * access to video memory planes. Do it with host palette * access disabled. */ inportb(_is1); outportb(ATC_REG_IW, 0x30); outportb(ATC_REG_IW, 0x01); /* Put ATC into graphics mode */ outportw(SEQ_REG_I, 0x0604); /* Planar mode */ outportw(GC_REG_I, 0x0005); /* Write Mode == Read Mode == 0 */ outportw(GC_REG_I, 0x0506); /* Switch GC to graphics mode and start VGA * memory at 0xA0000 (64KB) */ /* Now we're ready to read the first font. We'll do it using the slowest * copy routine possible. It is to account for the old VGA boards which may * lose data during too fast reads/writes. */ outportw(GC_REG_I, 0x0204); /* Reading from plane 2 */ slow_byte_copy ((char*)vram.data, (char*)regs->text_font1, VGA_FONT_SIZE); outportw(GC_REG_I, 0x0304); /* Reading from plane 3 */ slow_byte_copy ((char*)vram.data, (char*)regs->text_font2, VGA_FONT_SIZE); } /* __al_linux_restore_text_font: * Copy the saved font data back to video memory. */ static void __al_linux_restore_text_font(MODE_REGISTERS *regs) { ASSERT(regs); /* Same as in the previous routing. We're restoring the font in a * 4bpp mode to have access to separate memory planes. */ inportb(_is1); outportb(ATC_REG_IW, 0x30); outportb(ATC_REG_IW, 0x01); /* Put ATC into graphics mode */ outportw(SEQ_REG_I, 0x0604); /* Planar mode */ outportw(GC_REG_I, 0x0005); /* Write Mode == Read Mode == 0 */ outportw(GC_REG_I, 0x0506); /* Switch GC to graphics mode and start VGA * memory at 0xA0000 (64KB) */ outportw(GC_REG_I, 0x0001); if (regs->text_font1) { outportw(SEQ_REG_I, 0x0402); slow_byte_copy((char*)regs->text_font1, (char*)vram.data, VGA_FONT_SIZE); } if (regs->text_font2) { outportw(SEQ_REG_I, 0x0802); slow_byte_copy((char*)regs->text_font2, (char*)vram.data, VGA_FONT_SIZE); } } void __al_linux_screen_off(void) { _write_vga_register(SEQ_REG_I, 0x01, _read_vga_register(SEQ_REG_I, 0x01) | 0x20); inportb(_is1); __just_a_moment(); outportb(ATC_REG_IW, 0x00); __just_a_moment(); } void __al_linux_screen_on(void) { _write_vga_register(SEQ_REG_I, 0x01, _read_vga_register(SEQ_REG_I, 0x01) & 0xDF); inportb(_is1); __just_a_moment(); outportb(ATC_REG_IW, 0x20); __just_a_moment(); } void __al_linux_clear_vram (void) { memset (vram.data, 0, vram.size); } static MODE_REGISTERS txt_regs; void __al_linux_save_text_mode (void) { __al_linux_get_vga_regs (&txt_regs); __al_linux_save_palette (&txt_regs); __al_linux_save_text_font (&txt_regs); } void __al_linux_restore_text_mode (void) { __al_linux_restore_text_font (&txt_regs); __al_linux_restore_palette (&txt_regs); __al_linux_set_vga_regs (&txt_regs); } #endif /* ALLEGRO_LINUX_VGA */