vgabios: Add wrapper functions for accessing standard VGA registers.
[seabios.git] / vgasrc / stdvga.c
index 1727fcaafe4ae3f27b1e9376906c4d0e7f9fc9c0..0345a813f03d38cb1f2ef9866461be0f5c981c2d 100644 (file)
@@ -1,15 +1,16 @@
-// VGA io port access
+// Standard VGA driver code
 //
 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
-#include "stdvga.h" // vgahw_init
+#include "stdvga.h" // stdvga_init
 #include "ioport.h" // outb
 #include "farptr.h" // SET_FARVAR
-#include "biosvar.h" // GET_BDA
-#include "vgabios.h" // VGAREG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // memcpy_far
+#include "vbe.h" // VBE_RETURN_STATUS_FAILED
 
 // TODO
 //  * replace direct in/out calls with wrapper functions
  * Attribute control
  ****************************************************************/
 
-void
-vgahw_screen_disable(void)
+static void
+stdvga_screen_disable(void)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x00, VGAREG_ACTL_ADDRESS);
 }
 
-void
-vgahw_screen_enable(void)
+static void
+stdvga_screen_enable(void)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x20, VGAREG_ACTL_ADDRESS);
 }
 
 void
-vgahw_set_border_color(u8 color)
+stdvga_set_border_color(u8 color)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x00, VGAREG_ACTL_ADDRESS);
@@ -57,7 +58,7 @@ vgahw_set_border_color(u8 color)
 }
 
 void
-vgahw_set_overscan_border_color(u8 color)
+stdvga_set_overscan_border_color(u8 color)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x11, VGAREG_ACTL_ADDRESS);
@@ -66,7 +67,7 @@ vgahw_set_overscan_border_color(u8 color)
 }
 
 u8
-vgahw_get_overscan_border_color(void)
+stdvga_get_overscan_border_color(void)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x11, VGAREG_ACTL_ADDRESS);
@@ -77,7 +78,7 @@ vgahw_get_overscan_border_color(void)
 }
 
 void
-vgahw_set_palette(u8 palid)
+stdvga_set_palette(u8 palid)
 {
     inb(VGAREG_ACTL_RESET);
     palid &= 0x01;
@@ -94,27 +95,7 @@ vgahw_set_palette(u8 palid)
 }
 
 void
-vgahw_set_single_palette_reg(u8 reg, u8 val)
-{
-    inb(VGAREG_ACTL_RESET);
-    outb(reg, VGAREG_ACTL_ADDRESS);
-    outb(val, VGAREG_ACTL_WRITE_DATA);
-    outb(0x20, VGAREG_ACTL_ADDRESS);
-}
-
-u8
-vgahw_get_single_palette_reg(u8 reg)
-{
-    inb(VGAREG_ACTL_RESET);
-    outb(reg, VGAREG_ACTL_ADDRESS);
-    u8 v = inb(VGAREG_ACTL_READ_DATA);
-    inb(VGAREG_ACTL_RESET);
-    outb(0x20, VGAREG_ACTL_ADDRESS);
-    return v;
-}
-
-void
-vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
+stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
 {
     inb(VGAREG_ACTL_RESET);
     int i;
@@ -130,7 +111,7 @@ vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
 }
 
 void
-vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
+stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
 {
     int i;
     for (i = 0; i < 0x10; i++) {
@@ -147,7 +128,7 @@ vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
 }
 
 void
-vgahw_toggle_intensity(u8 flag)
+stdvga_toggle_intensity(u8 flag)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x10, VGAREG_ACTL_ADDRESS);
@@ -157,7 +138,7 @@ vgahw_toggle_intensity(u8 flag)
 }
 
 void
-vgahw_select_video_dac_color_page(u8 flag, u8 data)
+stdvga_select_video_dac_color_page(u8 flag, u8 data)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x10, VGAREG_ACTL_ADDRESS);
@@ -180,7 +161,7 @@ vgahw_select_video_dac_color_page(u8 flag, u8 data)
 }
 
 void
-vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
+stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
 {
     inb(VGAREG_ACTL_RESET);
     outb(0x10, VGAREG_ACTL_ADDRESS);
@@ -205,90 +186,60 @@ vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
  ****************************************************************/
 
 void
-vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
-{
-    outb(start, VGAREG_DAC_WRITE_ADDRESS);
-    while (count) {
-        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
-        data_far++;
-        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
-        data_far++;
-        outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
-        data_far++;
-        count--;
-    }
-}
-
-void
-vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
-{
-    outb(start, VGAREG_DAC_READ_ADDRESS);
-    while (count) {
-        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
-        data_far++;
-        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
-        data_far++;
-        SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
-        data_far++;
-        count--;
-    }
-}
-
-void
-vgahw_set_pel_mask(u8 val)
-{
-    outb(val, VGAREG_PEL_MASK);
-}
-
-u8
-vgahw_get_pel_mask(void)
-{
-    return inb(VGAREG_PEL_MASK);
-}
-
-void
-vgahw_save_dac_state(u16 seg, struct saveDACcolors *info)
+stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
 {
     /* XXX: check this */
     SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
     SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
     SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
-    vgahw_get_dac_regs(seg, info->dac, 0, 256);
+    stdvga_dac_read(seg, info->dac, 0, 256);
     SET_FARVAR(seg, info->color_select, 0);
 }
 
 void
-vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
+stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
 {
     outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
-    vgahw_set_dac_regs(seg, info->dac, 0, 256);
+    stdvga_dac_write(seg, info->dac, 0, 256);
     outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
 }
 
+void
+stdvga_perform_gray_scale_summing(u16 start, u16 count)
+{
+    stdvga_screen_disable();
+    int i;
+    for (i = start; i < start+count; i++) {
+        u8 rgb[3];
+        stdvga_dac_read(GET_SEG(SS), rgb, i, 1);
+
+        // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+        u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
+        if (intensity > 0x3f)
+            intensity = 0x3f;
+
+        stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
+    }
+    stdvga_screen_enable();
+}
+
 
 /****************************************************************
  * Memory control
  ****************************************************************/
 
 void
-vgahw_sequ_write(u8 index, u8 value)
+stdvga_set_text_block_specifier(u8 spec)
 {
-    outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
+    outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
 }
 
-void
-vgahw_grdc_write(u8 index, u8 value)
-{
-    outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
-}
 
-void
-vgahw_set_text_block_specifier(u8 spec)
-{
-    outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
-}
+/****************************************************************
+ * Font loading
+ ****************************************************************/
 
-void
+static void
 get_font_access(void)
 {
     outw(0x0100, VGAREG_SEQU_ADDRESS);
@@ -300,34 +251,50 @@ get_font_access(void)
     outw(0x0406, VGAREG_GRDC_ADDRESS);
 }
 
-void
+static void
 release_font_access(void)
 {
     outw(0x0100, VGAREG_SEQU_ADDRESS);
     outw(0x0302, VGAREG_SEQU_ADDRESS);
     outw(0x0304, VGAREG_SEQU_ADDRESS);
     outw(0x0300, VGAREG_SEQU_ADDRESS);
-    u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
+    u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
     outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
     outw(0x0004, VGAREG_GRDC_ADDRESS);
     outw(0x1005, VGAREG_GRDC_ADDRESS);
 }
 
+void
+stdvga_load_font(u16 seg, void *src_far, u16 count
+                 , u16 start, u8 destflags, u8 fontsize)
+{
+    get_font_access();
+    u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
+    void *dest_far = (void*)(blockaddr + start*32);
+    u16 i;
+    for (i = 0; i < count; i++)
+        memcpy_far(SEG_GRAPH, dest_far + i*32
+                   , seg, src_far + i*fontsize, fontsize);
+    release_font_access();
+}
+
 
 /****************************************************************
  * CRTC registers
  ****************************************************************/
 
-static u16
-get_crtc(void)
+u16
+stdvga_get_crtc(void)
 {
-    return GET_BDA(crtc_address);
+    if (stdvga_misc_read() & 1)
+        return VGAREG_VGA_CRTC_ADDRESS;
+    return VGAREG_MDA_CRTC_ADDRESS;
 }
 
 void
-vgahw_set_cursor_shape(u8 start, u8 end)
+stdvga_set_cursor_shape(u8 start, u8 end)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     outb(0x0a, crtc_addr);
     outb(start, crtc_addr + 1);
     outb(0x0b, crtc_addr);
@@ -335,9 +302,9 @@ vgahw_set_cursor_shape(u8 start, u8 end)
 }
 
 void
-vgahw_set_active_page(u16 address)
+stdvga_set_active_page(u16 address)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     outb(0x0c, crtc_addr);
     outb((address & 0xff00) >> 8, crtc_addr + 1);
     outb(0x0d, crtc_addr);
@@ -345,9 +312,9 @@ vgahw_set_active_page(u16 address)
 }
 
 void
-vgahw_set_cursor_pos(u16 address)
+stdvga_set_cursor_pos(u16 address)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     outb(0x0e, crtc_addr);
     outb((address & 0xff00) >> 8, crtc_addr + 1);
     outb(0x0f, crtc_addr);
@@ -355,9 +322,9 @@ vgahw_set_cursor_pos(u16 address)
 }
 
 void
-vgahw_set_scan_lines(u8 lines)
+stdvga_set_scan_lines(u8 lines)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     outb(0x09, crtc_addr);
     u8 crtc_r9 = inb(crtc_addr + 1);
     crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
@@ -366,9 +333,9 @@ vgahw_set_scan_lines(u8 lines)
 
 // Get vertical display end
 u16
-vgahw_get_vde(void)
+stdvga_get_vde(void)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     outb(0x12, crtc_addr);
     u16 vde = inb(crtc_addr + 1);
     outb(0x07, crtc_addr);
@@ -383,9 +350,9 @@ vgahw_get_vde(void)
  ****************************************************************/
 
 void
-vgahw_save_state(u16 seg, struct saveVideoHardware *info)
+stdvga_save_state(u16 seg, struct saveVideoHardware *info)
 {
-    u16 crtc_addr = get_crtc();
+    u16 crtc_addr = stdvga_get_crtc();
     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
@@ -427,7 +394,7 @@ vgahw_save_state(u16 seg, struct saveVideoHardware *info)
 }
 
 void
-vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
+stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
 {
     // Reset Attribute Ctl flip-flop
     inb(VGAREG_ACTL_RESET);
@@ -481,14 +448,59 @@ vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
 }
 
-void
-vgahw_set_mode(struct vgamode_s *vmode_g)
+static void
+clear_screen(struct vgamode_s *vmode_g)
+{
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case MM_TEXT:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+        break;
+    case MM_CGA:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
+        break;
+    default:
+        // XXX - old code gets/sets/restores sequ register 2 to 0xf -
+        // but it should always be 0xf anyway.
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
+    }
+}
+
+int
+stdvga_set_mode(int mode, int flags)
 {
+    // find the entry in the video modes
+    struct vgamode_s *vmode_g = stdvga_find_mode(mode);
+    dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
+    if (!vmode_g)
+        return VBE_RETURN_STATUS_FAILED;
+    struct stdvga_mode_s *stdmode_g = container_of(
+        vmode_g, struct stdvga_mode_s, info);
+
+    // if palette loading (bit 3 of modeset ctl = 0)
+    if (!(flags & MF_NOPALETTE)) {    // Set the PEL mask
+        stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
+
+        // From which palette
+        u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
+        u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
+
+        // Always 256*3 values
+        stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
+        u16 i;
+        for (i = palsize; i < 0x0100; i++) {
+            static u8 rgb[3] VAR16;
+            stdvga_dac_write(get_global_seg(), rgb, i, 1);
+        }
+
+        if (flags & MF_GRAYSUM)
+            stdvga_perform_gray_scale_summing(0x00, 0x100);
+    }
+
     // Reset Attribute Ctl flip-flop
     inb(VGAREG_ACTL_RESET);
 
     // Set Attribute Ctl
-    u8 *regs = GET_GLOBAL(vmode_g->actl_regs);
+    u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
     u16 i;
     for (i = 0; i <= 0x13; i++) {
         outb(i, VGAREG_ACTL_ADDRESS);
@@ -500,21 +512,21 @@ vgahw_set_mode(struct vgamode_s *vmode_g)
     // Set Sequencer Ctl
     outb(0, VGAREG_SEQU_ADDRESS);
     outb(0x03, VGAREG_SEQU_DATA);
-    regs = GET_GLOBAL(vmode_g->sequ_regs);
+    regs = GET_GLOBAL(stdmode_g->sequ_regs);
     for (i = 1; i <= 4; i++) {
         outb(i, VGAREG_SEQU_ADDRESS);
         outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
     }
 
     // Set Grafx Ctl
-    regs = GET_GLOBAL(vmode_g->grdc_regs);
+    regs = GET_GLOBAL(stdmode_g->grdc_regs);
     for (i = 0; i <= 8; i++) {
         outb(i, VGAREG_GRDC_ADDRESS);
         outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
     }
 
     // Set CRTC address VGA or MDA
-    u8 miscreg = GET_GLOBAL(vmode_g->miscreg);
+    u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
     if (!(miscreg & 1))
         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
@@ -522,7 +534,7 @@ vgahw_set_mode(struct vgamode_s *vmode_g)
     // Disable CRTC write protection
     outw(0x0011, crtc_addr);
     // Set CRTC regs
-    regs = GET_GLOBAL(vmode_g->crtc_regs);
+    regs = GET_GLOBAL(stdmode_g->crtc_regs);
     for (i = 0; i <= 0x18; i++) {
         outb(i, crtc_addr);
         outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
@@ -534,6 +546,20 @@ vgahw_set_mode(struct vgamode_s *vmode_g)
     // Enable video
     outb(0x20, VGAREG_ACTL_ADDRESS);
     inb(VGAREG_ACTL_RESET);
+
+    // Clear screen
+    if (!(flags & MF_NOCLEARMEM))
+        clear_screen(vmode_g);
+
+    // Write the fonts in memory
+    u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+    if (memmodel == MM_TEXT)
+        stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
+
+    // Setup BDA variables
+    modeswitch_set_bda(mode, flags, vmode_g);
+
+    return 0;
 }
 
 
@@ -542,19 +568,27 @@ vgahw_set_mode(struct vgamode_s *vmode_g)
  ****************************************************************/
 
 void
-vgahw_enable_video_addressing(u8 disable)
+stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+    SET_FARVAR(seg, *dest, 0xffff);
+}
+
+void
+stdvga_enable_video_addressing(u8 disable)
 {
     u8 v = (disable & 1) ? 0x00 : 0x02;
     u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
     outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
 }
 
-void
-vgahw_init(void)
+int
+stdvga_init(void)
 {
     // switch to color mode and enable CPU access 480 lines
     outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
     // more than 64k 3C4/04
     outb(0x04, VGAREG_SEQU_ADDRESS);
     outb(0x02, VGAREG_SEQU_DATA);
+
+    return 0;
 }