+2010-05-09 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Transform (broken) vga terminal into (working) vga video driver.
+
+ * conf/i386-pc.rmk (vga_mod_SOURCES): Change term/i386/pc/vga.c to
+ video/i386/pc/vga.c.
+ * include/grub/video.h (grub_video_driver_id):
+ Add GRUB_VIDEO_DRIVER_VGA.
+ * term/i386/pc/vga.c: Renamed to ...
+ * video/i386/pc/vga.c: ...this
+ (DEBUG_VGA): Removed.
+ (CHAR_WIDTH): Likewise.
+ (CHAR_HEIGHT): Likewise.
+ (TEXT_WIDTH): Likewise.
+ (TEXT_HEIGHT): Likewise.
+ (DEFAULT_FG_COLOR): Likewise.
+ (DEFAULT_BG_COLOR): Likewise.
+ (colored_char): Likewise.
+ (xpos): Likewise.
+ (ypos): Likewise.
+ (cursor_state): Likewise.
+ (fg_color): Likewise.
+ (bg_color): Likewise.
+ (text_buf): Likewise.
+ (page): Likewise.
+ (font): Likewise.
+ (framebuffer): New variable.
+ (set_read_map): Disabled.
+ (setup): New variable.
+ (is_target): Likewise.
+ (grub_vga_mod_init): Likewise.
+ (grub_vga_mod_fini): Likewise.
+ (check_vga_mem): Likewise.
+ (write_char): Likewise.
+ (write_cursor): Likewise.
+ (scroll_up): Likewise.
+ (grub_vga_putchar): Likewise.
+ (grub_vga_getcharwidth): Likewise.
+ (grub_vga_getwh): Likewise.
+ (grub_vga_getxy): Likewise.
+ (grub_vga_gotoxy): Likewise.
+ (grub_vga_cls): Likewise.
+ (grub_vga_setcolorstate): Likewise.
+ (grub_vga_setcursor): Likewise.
+ (grub_video_vga_init): New function.
+ (grub_video_vga_setup): Likewise.
+ (grub_video_vga_fini): Likewise.
+ (update_target): Likewise.
+ (grub_video_vga_blit_bitmap): Likewise.
+ (grub_video_vga_blit_render_target): Likewise.
+ (grub_video_vga_set_active_render_target): Likewise.
+ (grub_video_vga_get_active_render_target): Likewise.
+ (grub_video_vga_swap_buffers): Likewise.
+ (grub_video_vga_set_palette): Likewise.
+ (grub_video_vga_get_info_and_fini): Likewise.
+ (grub_vga_term): Removed.
+ (grub_video_vga_adapter): New variable.
+ (GRUB_MOD_INIT): Register a video driver instead of terminal.
+ (GRUB_MOD_FINI): Unrefister a video driver instead of terminal.
+
2010-05-05 Vladimir Serbinenko <phcoder@gmail.com>
* video/readers/jpeg.c: Indented.
vbetest_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For vga.mod.
-vga_mod_SOURCES = term/i386/pc/vga.c
+vga_mod_SOURCES = video/i386/pc/vga.c
vga_mod_CFLAGS = $(COMMON_CFLAGS)
vga_mod_LDFLAGS = $(COMMON_LDFLAGS)
GRUB_VIDEO_DRIVER_VBE,
GRUB_VIDEO_DRIVER_EFI_UGA,
GRUB_VIDEO_DRIVER_EFI_GOP,
- GRUB_VIDEO_DRIVER_SM712
+ GRUB_VIDEO_DRIVER_SM712,
+ GRUB_VIDEO_DRIVER_VGA
} grub_video_driver_id_t;
struct grub_video_adapter
+++ /dev/null
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
- *
- * GRUB 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.
- *
- * GRUB 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
-
-// TODO: Deprecated and broken. Needs to be converted to Video Driver!
-
-#include <grub/machine/vga.h>
-#include <grub/machine/console.h>
-#include <grub/cpu/io.h>
-#include <grub/term.h>
-#include <grub/types.h>
-#include <grub/dl.h>
-#include <grub/misc.h>
-#include <grub/font.h>
-
-#define DEBUG_VGA 0
-
-#define VGA_WIDTH 640
-#define VGA_HEIGHT 350
-#define CHAR_WIDTH 8
-#define CHAR_HEIGHT 16
-#define TEXT_WIDTH (VGA_WIDTH / CHAR_WIDTH)
-#define TEXT_HEIGHT (VGA_HEIGHT / CHAR_HEIGHT)
-#define VGA_MEM ((grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR)
-#define PAGE_OFFSET(x) ((x) * (VGA_WIDTH * VGA_HEIGHT / 8))
-
-#define DEFAULT_FG_COLOR 0xa
-#define DEFAULT_BG_COLOR 0x0
-
-struct colored_char
-{
- /* An Unicode codepoint. */
- grub_uint32_t code;
-
- /* Color indexes. */
- unsigned char fg_color;
- unsigned char bg_color;
-
- /* The width of this character minus one. */
- unsigned char width;
-
- /* The column index of this character. */
- unsigned char index;
-};
-
-static unsigned char text_mode;
-static unsigned xpos, ypos;
-static int cursor_state;
-static unsigned char fg_color, bg_color;
-static struct colored_char text_buf[TEXT_WIDTH * TEXT_HEIGHT];
-static unsigned char saved_map_mask;
-static int page = 0;
-static grub_font_t font = 0;
-
-#define SEQUENCER_ADDR_PORT 0x3C4
-#define SEQUENCER_DATA_PORT 0x3C5
-#define MAP_MASK_REGISTER 0x02
-
-#define CRTC_ADDR_PORT 0x3D4
-#define CRTC_DATA_PORT 0x3D5
-#define START_ADDR_HIGH_REGISTER 0x0C
-#define START_ADDR_LOW_REGISTER 0x0D
-
-#define GRAPHICS_ADDR_PORT 0x3CE
-#define GRAPHICS_DATA_PORT 0x3CF
-#define READ_MAP_REGISTER 0x04
-
-#define INPUT_STATUS1_REGISTER 0x3DA
-#define INPUT_STATUS1_VERTR_BIT 0x08
-
-static inline void
-wait_vretrace (void)
-{
- /* Wait until there is a vertical retrace. */
- while (! (grub_inb (INPUT_STATUS1_REGISTER) & INPUT_STATUS1_VERTR_BIT));
-}
-
-/* Get Map Mask Register. */
-static unsigned char
-get_map_mask (void)
-{
- unsigned char old_addr;
- unsigned char old_data;
-
- old_addr = grub_inb (SEQUENCER_ADDR_PORT);
- grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT);
-
- old_data = grub_inb (SEQUENCER_DATA_PORT);
-
- grub_outb (old_addr, SEQUENCER_ADDR_PORT);
-
- return old_data;
-}
-
-/* Set Map Mask Register. */
-static void
-set_map_mask (unsigned char mask)
-{
- unsigned char old_addr;
-
- old_addr = grub_inb (SEQUENCER_ADDR_PORT);
- grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT);
-
- grub_outb (mask, SEQUENCER_DATA_PORT);
-
- grub_outb (old_addr, SEQUENCER_ADDR_PORT);
-}
-
-/* Set Read Map Register. */
-static void
-set_read_map (unsigned char map)
-{
- unsigned char old_addr;
-
- old_addr = grub_inb (GRAPHICS_ADDR_PORT);
-
- grub_outb (READ_MAP_REGISTER, GRAPHICS_ADDR_PORT);
- grub_outb (map, GRAPHICS_DATA_PORT);
-
- grub_outb (old_addr, GRAPHICS_ADDR_PORT);
-}
-
-/* Set start address. */
-static void
-set_start_address (unsigned int start)
-{
- unsigned char old_addr;
-
- old_addr = grub_inb (CRTC_ADDR_PORT);
-
- grub_outb (START_ADDR_LOW_REGISTER, CRTC_ADDR_PORT);
- grub_outb (start & 0xFF, CRTC_DATA_PORT);
-
- grub_outb (START_ADDR_HIGH_REGISTER, CRTC_ADDR_PORT);
- grub_outb (start >> 8, CRTC_DATA_PORT);
-
- grub_outb (old_addr, CRTC_ADDR_PORT);
-}
-
-static grub_err_t
-grub_vga_mod_init (void)
-{
- text_mode = grub_vga_set_mode (0x10);
- cursor_state = 1;
- fg_color = DEFAULT_FG_COLOR;
- bg_color = DEFAULT_BG_COLOR;
- saved_map_mask = get_map_mask ();
- set_map_mask (0x0f);
- set_start_address (PAGE_OFFSET (page));
- font = grub_font_get (""); /* Choose any font, for now. */
- if (!font)
- return grub_error (GRUB_ERR_BAD_FONT, "no font loaded");
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_vga_mod_fini (void)
-{
- set_map_mask (saved_map_mask);
- grub_vga_set_mode (text_mode);
- return GRUB_ERR_NONE;
-}
-
-static int
-check_vga_mem (void *p)
-{
- return (p >= (void *) (VGA_MEM + PAGE_OFFSET (page))
- && p <= (void *) (VGA_MEM + PAGE_OFFSET (page)
- + VGA_WIDTH * VGA_HEIGHT / 8));
-}
-
-static void
-write_char (void)
-{
- struct colored_char *p = text_buf + xpos + ypos * TEXT_WIDTH;
- struct grub_font_glyph *glyph;
- unsigned char *mem_base;
- unsigned plane;
-
- mem_base = (VGA_MEM + xpos +
- ypos * CHAR_HEIGHT * TEXT_WIDTH + PAGE_OFFSET (page)) - p->index;
- p -= p->index;
-
- /* Get glyph for character. */
- glyph = grub_font_get_glyph (font, p->code);
-
- for (plane = 0x01; plane <= 0x08; plane <<= 1)
- {
- unsigned y;
- unsigned offset;
- unsigned char *mem;
-
- set_map_mask (plane);
-
- for (y = 0, offset = 0, mem = mem_base;
- y < CHAR_HEIGHT;
- y++, mem += TEXT_WIDTH)
- {
- /* TODO Re-implement glyph drawing for vga module. */
-#if 0
- unsigned i;
-
- unsigned char_width = 1; /* TODO Figure out wide characters. */
- for (i = 0; i < char_width && offset < 32; i++)
- {
- unsigned char fg_mask, bg_mask;
-
- fg_mask = (p->fg_color & plane) ? glyph->bitmap[offset] : 0;
- bg_mask = (p->bg_color & plane) ? ~(glyph->bitmap[offset]) : 0;
- offset++;
-
- if (check_vga_mem (mem + i))
- mem[i] = (fg_mask | bg_mask);
- }
-#endif /* 0 */
- }
- }
-
- set_map_mask (0x0f);
-}
-
-static void
-write_cursor (void)
-{
- unsigned char *mem = (VGA_MEM + PAGE_OFFSET (page) + xpos
- + (ypos * CHAR_HEIGHT + CHAR_HEIGHT - 3) * TEXT_WIDTH);
- if (check_vga_mem (mem))
- *mem = 0xff;
-
- mem += TEXT_WIDTH;
- if (check_vga_mem (mem))
- *mem = 0xff;
-}
-
-static void
-scroll_up (void)
-{
- unsigned i;
- unsigned plane;
-
- /* Do all the work in the other page. */
- grub_memmove (text_buf, text_buf + TEXT_WIDTH,
- sizeof (struct colored_char) * TEXT_WIDTH * (TEXT_HEIGHT - 1));
-
- for (i = TEXT_WIDTH * (TEXT_HEIGHT - 1); i < TEXT_WIDTH * TEXT_HEIGHT; i++)
- {
- text_buf[i].code = ' ';
- text_buf[i].fg_color = 0;
- text_buf[i].bg_color = 0;
- text_buf[i].width = 0;
- text_buf[i].index = 0;
- }
-
- for (plane = 1; plane <= 4; plane++)
- {
- set_read_map (plane);
- set_map_mask (1 << plane);
- grub_memmove (VGA_MEM + PAGE_OFFSET (1 - page), VGA_MEM
- + PAGE_OFFSET (page) + VGA_WIDTH * CHAR_HEIGHT / 8,
- VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8);
- }
-
- set_map_mask (0x0f);
- grub_memset (VGA_MEM + PAGE_OFFSET (1 - page)
- + VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8, 0,
- VGA_WIDTH * CHAR_HEIGHT / 8);
-
- /* Activate the other page. */
- page = 1 - page;
- wait_vretrace ();
- set_start_address (PAGE_OFFSET (page));
-}
-
-static void
-grub_vga_putchar (grub_uint32_t c)
-{
-#if DEBUG_VGA
- static int show = 1;
-#endif
-
- if (c == '\a')
- /* FIXME */
- return;
-
- if (c == '\b' || c == '\n' || c == '\r')
- {
- /* Erase current cursor, if any. */
- if (cursor_state)
- write_char ();
-
- switch (c)
- {
- case '\b':
- if (xpos > 0)
- xpos--;
- break;
-
- case '\n':
- if (ypos >= TEXT_HEIGHT - 1)
- scroll_up ();
- else
- ypos++;
- break;
-
- case '\r':
- xpos = 0;
- break;
- }
-
- if (cursor_state)
- write_cursor ();
- }
- else
- {
- struct grub_font_glyph *glyph;
- struct colored_char *p;
- unsigned char_width = 1;
-
- glyph = grub_font_get_glyph(font, c);
-
- if (xpos + char_width > TEXT_WIDTH)
- grub_putchar ('\n');
-
- p = text_buf + xpos + ypos * TEXT_WIDTH;
- p->code = c;
- p->fg_color = fg_color;
- p->bg_color = bg_color;
- p->width = char_width - 1;
- p->index = 0;
-
- if (char_width > 1)
- {
- unsigned i;
-
- for (i = 1; i < char_width; i++)
- {
- p[i].code = ' ';
- p[i].width = char_width - 1;
- p[i].index = i;
- }
- }
-
- write_char ();
-
- xpos += char_width;
- if (xpos >= TEXT_WIDTH)
- {
- xpos = 0;
-
- if (ypos >= TEXT_HEIGHT - 1)
- scroll_up ();
- else
- ypos++;
- }
-
- if (cursor_state)
- write_cursor ();
- }
-
-#if DEBUG_VGA
- if (show)
- {
- grub_uint16_t pos = grub_getxy ();
-
- show = 0;
- grub_gotoxy (0, 0);
- grub_printf ("[%u:%u]", (unsigned) (pos >> 8), (unsigned) (pos & 0xff));
- grub_gotoxy (pos >> 8, pos & 0xff);
- show = 1;
- }
-#endif
-}
-
-static grub_ssize_t
-grub_vga_getcharwidth (grub_uint32_t c)
-{
-#if 0
- struct grub_font_glyph glyph;
-
- glyph = grub_font_get_glyph (c);
-
- return glyph.char_width;
-#else
- (void) c; /* Prevent warning. */
- return 1; /* TODO Fix wide characters? */
-#endif
-}
-
-static grub_uint16_t
-grub_vga_getwh (void)
-{
- return (TEXT_WIDTH << 8) | TEXT_HEIGHT;
-}
-
-static grub_uint16_t
-grub_vga_getxy (void)
-{
- return ((xpos << 8) | ypos);
-}
-
-static void
-grub_vga_gotoxy (grub_uint8_t x, grub_uint8_t y)
-{
- if (x >= TEXT_WIDTH || y >= TEXT_HEIGHT)
- {
- grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)",
- (unsigned) x, (unsigned) y);
- return;
- }
-
- if (cursor_state)
- write_char ();
-
- xpos = x;
- ypos = y;
-
- if (cursor_state)
- write_cursor ();
-}
-
-static void
-grub_vga_cls (void)
-{
- unsigned i;
-
- wait_vretrace ();
- for (i = 0; i < TEXT_WIDTH * TEXT_HEIGHT; i++)
- {
- text_buf[i].code = ' ';
- text_buf[i].fg_color = 0;
- text_buf[i].bg_color = 0;
- text_buf[i].width = 0;
- text_buf[i].index = 0;
- }
-
- grub_memset (VGA_MEM + PAGE_OFFSET (page), 0, VGA_WIDTH * VGA_HEIGHT / 8);
-
- xpos = ypos = 0;
-}
-
-static void
-grub_vga_setcolorstate (grub_term_color_state state)
-{
- switch (state)
- {
- case GRUB_TERM_COLOR_STANDARD:
- case GRUB_TERM_COLOR_NORMAL:
- fg_color = DEFAULT_FG_COLOR;
- bg_color = DEFAULT_BG_COLOR;
- break;
- case GRUB_TERM_COLOR_HIGHLIGHT:
- fg_color = DEFAULT_BG_COLOR;
- bg_color = DEFAULT_FG_COLOR;
- break;
- default:
- break;
- }
-}
-
-static void
-grub_vga_setcursor (int on)
-{
- if (cursor_state != on)
- {
- if (cursor_state)
- write_char ();
- else
- write_cursor ();
-
- cursor_state = on;
- }
-}
-
-static struct grub_term_output grub_vga_term =
- {
- .name = "vga",
- .init = grub_vga_mod_init,
- .fini = grub_vga_mod_fini,
- .putchar = grub_vga_putchar,
- .getcharwidth = grub_vga_getcharwidth,
- .getwh = grub_vga_getwh,
- .getxy = grub_vga_getxy,
- .gotoxy = grub_vga_gotoxy,
- .cls = grub_vga_cls,
- .setcolorstate = grub_vga_setcolorstate,
- .setcursor = grub_vga_setcursor,
- .flags = 0,
- };
-
-GRUB_MOD_INIT(vga)
-{
- grub_term_register_output ("vga", &grub_vga_term);
-}
-
-GRUB_MOD_FINI(vga)
-{
- grub_term_unregister_output (&grub_vga_term);
-}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB 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.
+ *
+ * GRUB 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define grub_video_render_target grub_video_fbrender_target
+
+#include <grub/machine/vga.h>
+#include <grub/machine/console.h>
+#include <grub/cpu/io.h>
+#include <grub/mm.h>
+#include <grub/video.h>
+#include <grub/video_fb.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 350
+#define VGA_MEM ((grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR)
+#define PAGE_OFFSET(x) ((x) * (VGA_WIDTH * VGA_HEIGHT / 8))
+
+static unsigned char text_mode;
+static unsigned char saved_map_mask;
+
+static struct
+{
+ struct grub_video_mode_info mode_info;
+ struct grub_video_render_target *render_target;
+ grub_uint8_t *temporary_buffer;
+ int front_page;
+ int back_page;
+} framebuffer;
+
+#define SEQUENCER_ADDR_PORT 0x3C4
+#define SEQUENCER_DATA_PORT 0x3C5
+#define MAP_MASK_REGISTER 0x02
+
+#define CRTC_ADDR_PORT 0x3D4
+#define CRTC_DATA_PORT 0x3D5
+#define START_ADDR_HIGH_REGISTER 0x0C
+#define START_ADDR_LOW_REGISTER 0x0D
+
+#define GRAPHICS_ADDR_PORT 0x3CE
+#define GRAPHICS_DATA_PORT 0x3CF
+#define READ_MAP_REGISTER 0x04
+
+#define INPUT_STATUS1_REGISTER 0x3DA
+#define INPUT_STATUS1_VERTR_BIT 0x08
+
+static inline void
+wait_vretrace (void)
+{
+ /* Wait until there is a vertical retrace. */
+ while (! (grub_inb (INPUT_STATUS1_REGISTER) & INPUT_STATUS1_VERTR_BIT));
+}
+
+/* Get Map Mask Register. */
+static unsigned char
+get_map_mask (void)
+{
+ unsigned char old_addr;
+ unsigned char old_data;
+
+ old_addr = grub_inb (SEQUENCER_ADDR_PORT);
+ grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT);
+
+ old_data = grub_inb (SEQUENCER_DATA_PORT);
+
+ grub_outb (old_addr, SEQUENCER_ADDR_PORT);
+
+ return old_data;
+}
+
+/* Set Map Mask Register. */
+static void
+set_map_mask (unsigned char mask)
+{
+ unsigned char old_addr;
+
+ old_addr = grub_inb (SEQUENCER_ADDR_PORT);
+ grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT);
+
+ grub_outb (mask, SEQUENCER_DATA_PORT);
+
+ grub_outb (old_addr, SEQUENCER_ADDR_PORT);
+}
+
+#if 0
+/* Set Read Map Register. */
+static void
+set_read_map (unsigned char map)
+{
+ unsigned char old_addr;
+
+ old_addr = grub_inb (GRAPHICS_ADDR_PORT);
+
+ grub_outb (READ_MAP_REGISTER, GRAPHICS_ADDR_PORT);
+ grub_outb (map, GRAPHICS_DATA_PORT);
+
+ grub_outb (old_addr, GRAPHICS_ADDR_PORT);
+}
+#endif
+
+/* Set start address. */
+static void
+set_start_address (unsigned int start)
+{
+ unsigned char old_addr;
+
+ old_addr = grub_inb (CRTC_ADDR_PORT);
+
+ grub_outb (START_ADDR_LOW_REGISTER, CRTC_ADDR_PORT);
+ grub_outb (start & 0xFF, CRTC_DATA_PORT);
+
+ grub_outb (START_ADDR_HIGH_REGISTER, CRTC_ADDR_PORT);
+ grub_outb (start >> 8, CRTC_DATA_PORT);
+
+ grub_outb (old_addr, CRTC_ADDR_PORT);
+}
+
+static int setup = 0;
+static int is_target = 0;
+
+static grub_err_t
+grub_video_vga_init (void)
+{
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_video_vga_setup (unsigned int width, unsigned int height,
+ unsigned int mode_type, unsigned int mode_mask)
+{
+ grub_err_t err;
+
+ if ((width && width != VGA_WIDTH) || (height && height != VGA_HEIGHT))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found");
+
+ framebuffer.temporary_buffer = grub_malloc (VGA_HEIGHT * VGA_WIDTH);
+ framebuffer.front_page = 0;
+ framebuffer.back_page = 0;
+ if (!framebuffer.temporary_buffer)
+ return grub_errno;
+
+ saved_map_mask = get_map_mask ();
+
+ text_mode = grub_vga_set_mode (0x10);
+ setup = 1;
+ set_map_mask (0x0f);
+ set_start_address (PAGE_OFFSET (framebuffer.front_page));
+
+ framebuffer.mode_info.width = VGA_WIDTH;
+ framebuffer.mode_info.height = VGA_HEIGHT;
+
+ framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
+
+ if (grub_video_check_mode_flag (mode_type, mode_mask,
+ GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 1))
+ {
+ framebuffer.back_page = 1;
+ framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+ }
+
+ framebuffer.mode_info.bpp = 8;
+ framebuffer.mode_info.bytes_per_pixel = 1;
+ framebuffer.mode_info.pitch = VGA_WIDTH;
+ framebuffer.mode_info.number_of_colors = 16;
+ framebuffer.mode_info.red_mask_size = 0;
+ framebuffer.mode_info.red_field_pos = 0;
+ framebuffer.mode_info.green_mask_size = 0;
+ framebuffer.mode_info.green_field_pos = 0;
+ framebuffer.mode_info.blue_mask_size = 0;
+ framebuffer.mode_info.blue_field_pos = 0;
+ framebuffer.mode_info.reserved_mask_size = 0;
+ framebuffer.mode_info.reserved_field_pos = 0;
+
+ framebuffer.mode_info.blit_format
+ = grub_video_get_blit_format (&framebuffer.mode_info);
+
+ err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target,
+ &framebuffer.mode_info,
+ framebuffer.temporary_buffer);
+
+ if (err)
+ {
+ grub_dprintf ("video", "Couldn't create FB target\n");
+ return err;
+ }
+
+ is_target = 1;
+ err = grub_video_fb_set_active_render_target (framebuffer.render_target);
+
+ if (err)
+ return err;
+
+ err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
+ grub_video_fbstd_colors);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_video_vga_fini (void)
+{
+ if (setup)
+ {
+ set_map_mask (saved_map_mask);
+ grub_vga_set_mode (text_mode);
+ }
+ setup = 0;
+ grub_free (framebuffer.temporary_buffer);
+ framebuffer.temporary_buffer = 0;
+ return GRUB_ERR_NONE;
+}
+
+static inline void
+update_target (void)
+{
+ int plane;
+
+ if (!is_target)
+ return;
+
+ for (plane = 0x01; plane <= 0x08; plane <<= 1)
+ {
+ grub_uint8_t *ptr;
+ volatile grub_uint8_t *ptr2;
+ unsigned cbyte = 0;
+ int shift = 7;
+ set_map_mask (plane);
+ for (ptr = framebuffer.temporary_buffer,
+ ptr2 = VGA_MEM + PAGE_OFFSET (framebuffer.back_page);
+ ptr < framebuffer.temporary_buffer + VGA_WIDTH * VGA_HEIGHT; ptr++)
+ {
+ cbyte |= (!!(plane & *ptr)) << shift;
+ shift--;
+ if (shift == -1)
+ {
+ *ptr2++ = cbyte;
+ shift = 7;
+ cbyte = 0;
+ }
+ }
+ }
+}
+
+static grub_err_t
+grub_video_vga_blit_bitmap (struct grub_video_bitmap *bitmap,
+ enum grub_video_blit_operators oper, int x, int y,
+ int offset_x, int offset_y,
+ unsigned int width, unsigned int height)
+{
+ grub_err_t ret;
+ ret = grub_video_fb_blit_bitmap (bitmap, oper, x, y, offset_x, offset_y,
+ width, height);
+ update_target ();
+ return ret;
+}
+
+static grub_err_t
+grub_video_vga_blit_render_target (struct grub_video_fbrender_target *source,
+ enum grub_video_blit_operators oper,
+ int x, int y, int offset_x, int offset_y,
+ unsigned int width, unsigned int height)
+{
+ grub_err_t ret;
+
+ ret = grub_video_fb_blit_render_target (source, oper, x, y,
+ offset_x, offset_y, width, height);
+ update_target ();
+
+ return ret;
+}
+
+static grub_err_t
+grub_video_vga_set_active_render_target (struct grub_video_render_target *target)
+{
+ if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
+ {
+ is_target = 1;
+ target = framebuffer.render_target;
+ }
+ else
+ is_target = 0;
+
+ return grub_video_fb_set_active_render_target (target);
+}
+
+static grub_err_t
+grub_video_vga_get_active_render_target (struct grub_video_render_target **target)
+{
+ grub_err_t err;
+ err = grub_video_fb_get_active_render_target (target);
+ if (err)
+ return err;
+
+ if (*target == framebuffer.render_target)
+ *target = GRUB_VIDEO_RENDER_TARGET_DISPLAY;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_video_vga_swap_buffers (void)
+{
+ if (!(framebuffer.mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED))
+ return GRUB_ERR_NONE;
+
+ /* Activate the other page. */
+ framebuffer.front_page = !framebuffer.front_page;
+ framebuffer.back_page = !framebuffer.back_page;
+ wait_vretrace ();
+ set_start_address (PAGE_OFFSET (framebuffer.front_page));
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_video_vga_set_palette (unsigned int start __attribute__ ((unused)),
+ unsigned int count __attribute__ ((unused)),
+ struct grub_video_palette_data *palette_data __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_IO, "can't change palette");
+}
+
+static grub_err_t
+grub_video_vga_get_info_and_fini (struct grub_video_mode_info *mode_info,
+ void **framebuf)
+{
+ set_map_mask (0xf);
+
+ grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
+ mode_info->bpp = 1;
+ mode_info->bytes_per_pixel = 0;
+ mode_info->pitch = VGA_WIDTH / 8;
+ mode_info->number_of_colors = 1;
+
+ mode_info->bg_red = 0;
+ mode_info->bg_green = 0;
+ mode_info->bg_blue = 0;
+ mode_info->bg_alpha = 255;
+
+ mode_info->fg_red = 255;
+ mode_info->fg_green = 255;
+ mode_info->fg_blue = 255;
+ mode_info->fg_alpha = 255;
+
+ *framebuf = VGA_MEM + PAGE_OFFSET (framebuffer.front_page);
+
+ grub_video_fb_fini ();
+ grub_free (framebuffer.temporary_buffer);
+ framebuffer.temporary_buffer = 0;
+ setup = 0;
+
+ return GRUB_ERR_NONE;
+}
+
+
+static struct grub_video_adapter grub_video_vga_adapter =
+ {
+ .name = "VGA Video Driver",
+ .id = GRUB_VIDEO_DRIVER_VGA,
+
+ .init = grub_video_vga_init,
+ .fini = grub_video_vga_fini,
+ .setup = grub_video_vga_setup,
+ .get_info = grub_video_fb_get_info,
+ .get_info_and_fini = grub_video_vga_get_info_and_fini,
+ .set_palette = grub_video_vga_set_palette,
+ .get_palette = grub_video_fb_get_palette,
+ .set_viewport = grub_video_fb_set_viewport,
+ .get_viewport = grub_video_fb_get_viewport,
+ .map_color = grub_video_fb_map_color,
+ .map_rgb = grub_video_fb_map_rgb,
+ .map_rgba = grub_video_fb_map_rgba,
+ .unmap_color = grub_video_fb_unmap_color,
+ .fill_rect = grub_video_fb_fill_rect,
+ .blit_bitmap = grub_video_vga_blit_bitmap,
+ .blit_render_target = grub_video_vga_blit_render_target,
+ .scroll = grub_video_fb_scroll,
+ .swap_buffers = grub_video_vga_swap_buffers,
+ .create_render_target = grub_video_fb_create_render_target,
+ .delete_render_target = grub_video_fb_delete_render_target,
+ .set_active_render_target = grub_video_vga_set_active_render_target,
+ .get_active_render_target = grub_video_vga_get_active_render_target,
+
+ .next = 0
+ };
+
+GRUB_MOD_INIT(vga)
+{
+ grub_video_register (&grub_video_vga_adapter);
+}
+
+GRUB_MOD_FINI(vga)
+{
+ grub_video_unregister (&grub_video_vga_adapter);
+}