vgabios: Implement VBE save/restore state function (func 04).
[seabios.git] / vgasrc / vbe.c
index c1b03f0aff7d1b9cff37bd5d0b926fe8cba0da47..505cb61cbea902c352b195ec2e9258e041c93ecc 100644 (file)
@@ -1,6 +1,7 @@
 // Video Bios Extensions handlers
 //
-// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2012  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2011  Julian Pidancet <julian.pidancet@citrix.com>
 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -107,25 +108,20 @@ vbe_104f01(struct bregs *regs)
                , SEGOFF(get_global_seg(), (u32)entry_104f05));
     int width = GET_GLOBAL(vmode_g->width);
     int height = GET_GLOBAL(vmode_g->height);
-    int linesize = width * DIV_ROUND_UP(depth, 8);
+    int linesize = DIV_ROUND_UP(width * vga_bpp(vmode_g), 8);
     SET_FARVAR(seg, info->bytes_per_scanline, linesize);
     SET_FARVAR(seg, info->xres, width);
     SET_FARVAR(seg, info->yres, height);
     SET_FARVAR(seg, info->xcharsize, GET_GLOBAL(vmode_g->cwidth));
     SET_FARVAR(seg, info->ycharsize, GET_GLOBAL(vmode_g->cheight));
-    if (depth == 4)
-        SET_FARVAR(seg, info->planes, 4);
-    else
-        SET_FARVAR(seg, info->planes, 1);
+    int planes = (depth == 4) ? 4 : 1;
+    SET_FARVAR(seg, info->planes, planes);
     SET_FARVAR(seg, info->bits_per_pixel, depth);
     SET_FARVAR(seg, info->banks, 1);
     SET_FARVAR(seg, info->mem_model, GET_GLOBAL(vmode_g->memmodel));
     SET_FARVAR(seg, info->bank_size, 0);
     u32 pages = GET_GLOBAL(VBE_total_memory) / (height * linesize);
-    if (depth == 4)
-        SET_FARVAR(seg, info->pages, (pages / 4) - 1);
-    else
-        SET_FARVAR(seg, info->pages, pages - 1);
+    SET_FARVAR(seg, info->pages, (pages / planes) - 1);
     SET_FARVAR(seg, info->reserved0, 1);
 
     u8 r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
@@ -205,8 +201,36 @@ vbe_104f03(struct bregs *regs)
 static void
 vbe_104f04(struct bregs *regs)
 {
-    debug_stub(regs);
-    regs->ax = 0x0100;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    u16 states = regs->cx;
+    if (states & ~0x0f)
+        goto fail;
+    int ret;
+    switch (regs->dl) {
+    case 0x00:
+        ret = vgahw_size_state(states);
+        if (ret < 0)
+            goto fail;
+        regs->bx = ret / 64;
+        break;
+    case 0x01:
+        ret = vgahw_save_state(seg, data, states);
+        if (ret)
+            goto fail;
+        break;
+    case 0x02:
+        ret = vgahw_restore_state(seg, data, states);
+        if (ret)
+            goto fail;
+        break;
+    default:
+        goto fail;
+    }
+    regs->ax = 0x004f;
+    return;
+fail:
+    regs->ax = 0x014f;
 }
 
 void VISIBLE16
@@ -309,8 +333,29 @@ fail:
 static void
 vbe_104f08(struct bregs *regs)
 {
-    debug_stub(regs);
-    regs->ax = 0x0100;
+    struct vgamode_s *vmode_g = get_current_mode();
+    if (! vmode_g)
+        goto fail;
+    u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+    if (memmodel == MM_DIRECT || memmodel == MM_YUV) {
+        regs->ax = 0x034f;
+        return;
+    }
+    if (regs->bl > 1)
+        goto fail;
+    if (regs->bl == 0) {
+        int ret = vgahw_set_dacformat(vmode_g, regs->bh);
+        if (ret < 0)
+            goto fail;
+    }
+    int ret = vgahw_get_dacformat(vmode_g);
+    if (ret < 0)
+        goto fail;
+    regs->bh = ret;
+    regs->ax = 0x004f;
+    return;
+fail:
+    regs->ax = 0x014f;
 }
 
 static void