diff options
Diffstat (limited to 'mubios/drivers/vga.c')
| -rw-r--r-- | mubios/drivers/vga.c | 267 |
1 files changed, 211 insertions, 56 deletions
diff --git a/mubios/drivers/vga.c b/mubios/drivers/vga.c index 16f88e5..4bd14b1 100644 --- a/mubios/drivers/vga.c +++ b/mubios/drivers/vga.c @@ -6,83 +6,211 @@ This file is part of RCC-Project. RCC-Project is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 3 of the License, or (at your option) any later - version. - */ + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) any + later version. -#include "bios.h" -#include "io.h" + RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. -#define VGA_TEXT_BASE 0x000B8000u -#define VGA_TEXT_CELLS 2000u + You should have received a copy of the GNU General Public License along with + RCC-Project; see the file COPYING. If not see + <http://www.gnu.org/licenses/>. + */ -#define BDA_VIDEO_MODE 0x0049u -#define BDA_VIDEO_COLUMNS 0x004Au -#define BDA_VIDEO_PAGE_SIZE 0x004Cu -#define BDA_VIDEO_PAGE 0x0062u -#define BDA_CURSOR_BASE 0x0450u -#define BDA_CURSOR_SHAPE 0x0460u +#include "vga.h" +#include "io.h" +#include "vbe.h" #define VGA_MISC_OUTPUT_WRITE 0x03C2u #define VGA_SEQ_INDEX 0x03C4u -#define VGA_SEQ_DATA 0x03C5u #define VGA_CRTC_INDEX 0x03D4u -#define VGA_CRTC_DATA 0x03D5u #define VGA_GC_INDEX 0x03CEu -#define VGA_GC_DATA 0x03CFu #define VGA_INPUT_STATUS 0x03DAu #define VGA_ATTR_INDEX_DATA 0x03C0u +#define VGA_PEL_MASK 0x03C6u +#define VGA_DAC_WRITE_INDEX 0x03C8u +#define VGA_DAC_DATA 0x03C9u +#define VGA_FONT_BASE 0x000A0000u + +static void +vga_write_register (u16 port, u8 index, u8 value) +{ + io_out8 (port, index); + io_out8 ((u16)(port + 1u), value); +} static void -vga_write_registers (u16 index_port, u16 data_port, const u8 *values, u8 count) +vga_write_registers (u16 port, const u8 *values, u8 count) { u8 index; for (index = 0; index < count; ++index) + vga_write_register (port, index, values[index]); +} + +static void +vga_load_font (void) +{ + volatile u8 *plane = (volatile u8 *)VGA_FONT_BASE; + u16 character; + u8 line; + + /* Select plane 2 and disable odd/even addressing while writing glyphs. */ + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x01u); + vga_write_register (VGA_SEQ_INDEX, 0x02u, 0x04u); + vga_write_register (VGA_SEQ_INDEX, 0x04u, 0x07u); + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x03u); + vga_write_register (VGA_GC_INDEX, 0x04u, 0x02u); + vga_write_register (VGA_GC_INDEX, 0x05u, 0x00u); + vga_write_register (VGA_GC_INDEX, 0x06u, 0x04u); + + for (character = 0; character < 256u; ++character) { - io_out8 (index_port, index); - io_out8 (data_port, values[index]); + for (line = 0; line < VGA_FONT_HEIGHT; ++line) + plane[character * 32u + line] + = vga_font_8x16[character * VGA_FONT_HEIGHT + line]; + for (; line < 32u; ++line) + plane[character * 32u + line] = 0u; + } + + /* Restore the B8000 text aperture and character/attribute plane mapping. */ + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x01u); + vga_write_register (VGA_SEQ_INDEX, 0x02u, 0x03u); + vga_write_register (VGA_SEQ_INDEX, 0x03u, 0x00u); + vga_write_register (VGA_SEQ_INDEX, 0x04u, 0x03u); + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x03u); + vga_write_register (VGA_GC_INDEX, 0x06u, 0x0Eu); + vga_write_register (VGA_GC_INDEX, 0x04u, 0x00u); + vga_write_register (VGA_GC_INDEX, 0x05u, 0x10u); +} + +static void +vga_load_palette (void) +{ + u16 index; + + io_out8 (VGA_PEL_MASK, 0xFFu); + io_out8 (VGA_DAC_WRITE_INDEX, 0u); + /* Mode 03h uses the 64 EGA colors, each DAC component is six bits. */ + for (index = 0; index < 64u; ++index) + { + io_out8 (VGA_DAC_DATA, (u8)(((index >> 2) & 1u) * 0x2Au + + ((index >> 5) & 1u) * 0x15u)); + io_out8 (VGA_DAC_DATA, (u8)(((index >> 1) & 1u) * 0x2Au + + ((index >> 4) & 1u) * 0x15u)); + io_out8 (VGA_DAC_DATA, + (u8)((index & 1u) * 0x2Au + ((index >> 3) & 1u) * 0x15u)); + } + for (; index < 256u; ++index) + { + io_out8 (VGA_DAC_DATA, 0u); + io_out8 (VGA_DAC_DATA, 0u); + io_out8 (VGA_DAC_DATA, 0u); } } void -vga_text_mode_init (void) +vga_set_cursor_shape (u16 shape) +{ + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; + u8 start = (u8)((shape >> 8) & 0x3Fu); + u8 end = (u8)(shape & 0x1Fu); + u16 height = *(volatile u16 *)(bda + BDA_VIDEO_HEIGHT); + + *(volatile u16 *)(bda + BDA_CURSOR_SHAPE) = shape; + /* VGA BIOS scales an eight-scanline cursor unless emulation is disabled. + Start bit 5 disables the cursor and must not be scaled. */ + if ((bda[BDA_VIDEO_CTL] & 1u) == 0u && height > 8u && end < 8u + && start < 0x20u) + { + if (end != start + 1u) + start = (u8)(((start + 1u) * height / 8u) - 1u); + else + start = (u8)(((end + 1u) * height / 8u) - 2u); + end = (u8)(((end + 1u) * height / 8u) - 1u); + } + vga_write_register (VGA_CRTC_INDEX, 0x0Au, start); + vga_write_register (VGA_CRTC_INDEX, 0x0Bu, end); +} + +void +vga_set_cursor_position (u8 page, u16 position) +{ + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; + u16 address; + + /* INT 10h exposes eight text pages. */ + if (page >= VGA_PAGE_COUNT) + return; + + *(volatile u16 *)(bda + BDA_CURSOR_BASE + page * 2u) = position; + if (page != bda[BDA_VIDEO_PAGE]) + return; + + address = (u16)(page * (VGA_PAGE_SIZE / 2u) + (position >> 8) * VGA_COLUMNS + + (position & 0xFFu)); + vga_write_register (VGA_CRTC_INDEX, 0x0Eu, (u8)(address >> 8)); + vga_write_register (VGA_CRTC_INDEX, 0x0Fu, (u8)address); +} + +void +vga_set_active_page (u8 page) { - static const u8 sequencer[] = { 0x00u, 0x00u, 0x03u, 0x00u, 0x02u }; + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; + u16 offset; + + /* Each page occupies 4 KiB within the 32 KiB text aperture. */ + if (page >= VGA_PAGE_COUNT) + return; + + offset = (u16)(page * VGA_PAGE_SIZE); + bda[BDA_VIDEO_PAGE] = page; + *(volatile u16 *)(bda + BDA_VIDEO_PAGE_START) = offset; + vga_write_register (VGA_CRTC_INDEX, 0x0Cu, (u8)((offset / 2u) >> 8)); + vga_write_register (VGA_CRTC_INDEX, 0x0Du, (u8)(offset / 2u)); + vga_set_cursor_position ( + page, *(volatile u16 *)(bda + BDA_CURSOR_BASE + page * 2u)); +} + +void +vga_text_mode_set (u8 preserve) +{ + /* Standard VGA 80x25, 720x400 mode 03h values, as used by SeaVGABIOS. */ + static const u8 sequencer[] = { 0x01u, 0x00u, 0x03u, 0x00u, 0x02u }; static const u8 crtc[] = { 0x5Fu, 0x4Fu, 0x50u, 0x82u, 0x55u, 0x81u, 0xBFu, 0x1Fu, 0x00u, 0x4Fu, 0x0Du, 0x0Eu, 0x00u, 0x00u, 0x00u, 0x00u, 0x9Cu, 0x8Eu, 0x8Fu, 0x28u, 0x1Fu, 0x96u, 0xB9u, 0xA3u, 0xFFu }; static const u8 graphics[] - = { 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x0Fu, 0x00u, 0xFFu }; + = { 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x10u, 0x0Eu, 0x0Fu, 0xFFu }; static const u8 attributes[] - = { 0x00u, 0x01u, 0x02u, 0x03u, 0x04u, 0x05u, 0x06u, - 0x07u, 0x08u, 0x09u, 0x0Au, 0x0Bu, 0x0Cu, 0x0Du, - 0x0Eu, 0x0Fu, 0x0Cu, 0x00u, 0x0Fu, 0x08u, 0x00u }; - volatile u16 *video; - volatile u8 *bda; + = { 0x00u, 0x01u, 0x02u, 0x03u, 0x04u, 0x05u, 0x14u, + 0x07u, 0x38u, 0x39u, 0x3Au, 0x3Bu, 0x3Cu, 0x3Du, + 0x3Eu, 0x3Fu, 0x0Cu, 0x00u, 0x0Fu, 0x08u, 0x00u }; + volatile u16 *video = (volatile u16 *)VGA_TEXT_BASE; + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; + u32 font_address = (u32)vga_font_8x16; + volatile u16 *font_vector = (volatile u16 *)(0x43u * 4u); u16 cell; u8 index; - io_out8 (VGA_MISC_OUTPUT_WRITE, 0x67u); + vbe_leave_graphics (); - io_out8 (VGA_SEQ_INDEX, 0x00u); - io_out8 (VGA_SEQ_DATA, 0x01u); - for (index = 1; index < 5u; ++index) - { - io_out8 (VGA_SEQ_INDEX, index); - io_out8 (VGA_SEQ_DATA, sequencer[index]); - } - io_out8 (VGA_SEQ_INDEX, 0x00u); - io_out8 (VGA_SEQ_DATA, 0x03u); - - io_out8 (VGA_CRTC_INDEX, 0x11u); - io_out8 (VGA_CRTC_DATA, 0x00u); - vga_write_registers (VGA_CRTC_INDEX, VGA_CRTC_DATA, crtc, 25); - - vga_write_registers (VGA_GC_INDEX, VGA_GC_DATA, graphics, 9); + /* Keep attribute-controller output blank until registers and RAM are ready. + */ + io_in8 (VGA_INPUT_STATUS); + io_out8 (VGA_ATTR_INDEX_DATA, 0x00u); + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x01u); + io_out8 (VGA_MISC_OUTPUT_WRITE, 0x67u); + vga_write_registers (VGA_SEQ_INDEX, sequencer, 5u); + vga_write_register (VGA_SEQ_INDEX, 0x00u, 0x03u); + /* Clear CRTC write protection before programming timing registers. */ + vga_write_register (VGA_CRTC_INDEX, 0x11u, 0x00u); + vga_write_registers (VGA_CRTC_INDEX, crtc, 25u); + vga_write_registers (VGA_GC_INDEX, graphics, 9u); for (index = 0; index < 21u; ++index) { io_in8 (VGA_INPUT_STATUS); @@ -90,20 +218,47 @@ vga_text_mode_init (void) io_out8 (VGA_ATTR_INDEX_DATA, attributes[index]); } + vga_load_palette (); + vga_load_font (); + + /* AL bit 7 requests a mode change without clearing text video memory. */ + if (preserve == 0u) + for (cell = 0; cell < VGA_PAGE_COUNT * VGA_PAGE_SIZE / 2u; ++cell) + video[cell] = 0x0720u; + + bda[BDA_VIDEO_MODE] = 0x03u; + *(volatile u16 *)(bda + BDA_VIDEO_COLUMNS) = VGA_COLUMNS; + *(volatile u16 *)(bda + BDA_VIDEO_PAGE_SIZE) = VGA_PAGE_SIZE; + for (index = 0; index < VGA_PAGE_COUNT; ++index) + *(volatile u16 *)(bda + BDA_CURSOR_BASE + index * 2u) = 0u; + *(volatile u16 *)(bda + BDA_VIDEO_CRTC) = VGA_CRTC_INDEX; + bda[BDA_VIDEO_MSR] = 0x29u; + bda[BDA_VIDEO_PALETTE] = 0u; + bda[BDA_VIDEO_ROWS] = VGA_ROWS - 1u; + *(volatile u16 *)(bda + BDA_VIDEO_HEIGHT) = VGA_FONT_HEIGHT; + bda[BDA_VIDEO_CTL] = (u8)(0x60u | (preserve & 0x80u)); + vbe.current_mode = (u16)(0x03u | ((u16)(preserve & 0x80u) << 8)); + bda[BDA_VIDEO_SWITCHES] = 0xF9u; + bda[BDA_VIDEO_MODESET_CTL] &= 0x7Fu; + bda[BDA_VIDEO_DCC] = 0x08u; + + /* INT 43h identifies the ROM font through a real-mode segment:offset. */ + font_vector[0] = (u16)(font_address & 0x0Fu); + font_vector[1] = (u16)(font_address >> 4); + vga_set_cursor_shape (0x0607u); + vga_set_active_page (0u); + io_in8 (VGA_INPUT_STATUS); io_out8 (VGA_ATTR_INDEX_DATA, 0x20u); +} - video = (volatile u16 *)VGA_TEXT_BASE; - for (cell = 0; cell < VGA_TEXT_CELLS; ++cell) - video[cell] = 0x0720u; +void +vga_text_mode_init (void) +{ + volatile u8 *bda = (volatile u8 *)MUBIOS_BDA_BASE; - bda = (volatile u8 *)MUBIOS_BDA_BASE; - bda[BDA_VIDEO_MODE] = 0x03u; - bda[BDA_VIDEO_PAGE] = 0x00u; - bda[BDA_VIDEO_COLUMNS] = 80u; - bda[BDA_VIDEO_COLUMNS + 1u] = 0u; - bda[BDA_VIDEO_PAGE_SIZE] = 0x00u; - bda[BDA_VIDEO_PAGE_SIZE + 1u] = 0x10u; - *(volatile u16 *)(bda + BDA_CURSOR_BASE) = 0u; - *(volatile u16 *)(bda + BDA_CURSOR_SHAPE) = 0x0607u; + /* VGA is present, with a color display and the default 400-line timing. */ + bda[BDA_VIDEO_MODESET_CTL] = 0x51u; + vbe_init (); + vga_text_mode_set (0u); } |
