VGA: Simplify scrolling implementation.
[seabios.git] / vgasrc / vga.c
index 70e05b5758c48bdd8518db407f39def17dec247c..c28d8915f3dee27c592f66a9993e5a097522f95d 100644 (file)
@@ -7,7 +7,6 @@
 
 
 // TODO:
-//  * define structs for save/restore state
 //  * review correctness of converted asm by comparing with RBIL
 //  * refactor redundant code into sub-functions
 //  * See if there is a method to the in/out stuff that can be encapsulated.
@@ -15,8 +14,6 @@
 //  * verify all funcs static
 //
 //  * convert vbe/clext code
-//
-//  * extract hw code from bios interfaces
 
 #include "bregs.h" // struct bregs
 #include "biosvar.h" // GET_BDA
 
 #define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
 
-
-// ===================================================================
-//
-// Video Utils
-//
-// ===================================================================
-
-// -------------------------------------------------------------------
-inline void
+static inline void
 call16_vgaint(u32 eax, u32 ebx)
 {
     asm volatile(
@@ -53,14 +42,6 @@ call16_vgaint(u32 eax, u32 ebx)
         : "cc", "memory");
 }
 
-
-// ===================================================================
-//
-// BIOS functions
-//
-// ===================================================================
-
-// -------------------------------------------------------------------
 static void
 biosfn_perform_gray_scale_summing(u16 start, u16 count)
 {
@@ -80,7 +61,6 @@ biosfn_perform_gray_scale_summing(u16 start, u16 count)
     vgahw_screen_enable();
 }
 
-// -------------------------------------------------------------------
 static void
 biosfn_set_cursor_shape(u8 CH, u8 CL)
 {
@@ -111,45 +91,48 @@ biosfn_get_cursor_shape(u8 page)
     return GET_BDA(cursor_type);
 }
 
-// -------------------------------------------------------------------
 static void
-biosfn_set_cursor_pos(u8 page, u16 cursor)
+set_cursor_pos(struct cursorpos cp)
 {
     // Should not happen...
-    if (page > 7)
+    if (cp.page > 7)
         return;
 
     // Bios cursor pos
-    SET_BDA(cursor_pos[page], cursor);
+    SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
 
     // Set the hardware cursor
     u8 current = GET_BDA(video_page);
-    if (page != current)
+    if (cp.page != current)
         return;
 
     // Get the dimensions
     u16 nbcols = GET_BDA(video_cols);
     u16 nbrows = GET_BDA(video_rows) + 1;
 
-    u8 xcurs = cursor & 0x00ff;
-    u8 ycurs = (cursor & 0xff00) >> 8;
-
     // Calculate the address knowing nbcols nbrows and page num
-    u16 address = SCREEN_IO_START(nbcols, nbrows, page) + xcurs + ycurs * nbcols;
+    u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
+                   + cp.x + cp.y * nbcols);
 
     vgahw_set_cursor_pos(address);
 }
 
-u16
-biosfn_get_cursor_pos(u8 page)
+static struct cursorpos
+get_cursor_pos(u8 page)
 {
-    if (page > 7)
-        return 0;
+    if (page == 0xff)
+        // special case - use current page
+        page = GET_BDA(video_page);
+    if (page > 7) {
+        struct cursorpos cp = { 0, 0, 0xfe };
+        return cp;
+    }
     // FIXME should handle VGA 14/16 lines
-    return GET_BDA(cursor_pos[page]);
+    u16 xy = GET_BDA(cursor_pos[page]);
+    struct cursorpos cp = {xy, xy>>8, page};
+    return cp;
 }
 
-// -------------------------------------------------------------------
 static void
 biosfn_set_active_page(u8 page)
 {
@@ -162,10 +145,10 @@ biosfn_set_active_page(u8 page)
         return;
 
     // Get pos curs pos for the right page
-    u16 cursor = biosfn_get_cursor_pos(page);
+    struct cursorpos cp = get_cursor_pos(page);
 
     u16 address;
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
         // Get the dimensions
         u16 nbcols = GET_BDA(video_cols);
         u16 nbrows = GET_BDA(video_rows) + 1;
@@ -189,12 +172,178 @@ biosfn_set_active_page(u8 page)
     dprintf(1, "Set active page %02x address %04x\n", page, address);
 
     // Display the cursor, now the page is active
-    biosfn_set_cursor_pos(page, cursor);
+    set_cursor_pos(cp);
+}
+
+static struct cursorpos
+check_scroll(struct cursorpos cp)
+{
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    // Do we need to wrap ?
+    if (cp.x == nbcols) {
+        cp.x = 0;
+        cp.y++;
+    }
+    // Do we need to scroll ?
+    if (cp.y == nbrows) {
+        struct cursorpos ul = {0, 0, cp.page};
+        struct cursorpos lr = {nbcols-1, nbrows-1, cp.page};
+        vgafb_scroll(1, -1, ul, lr);
+        cp.y--;
+    }
+
+    return cp;
+}
+
+static struct cursorpos
+write_teletype(struct cursorpos cp, struct carattr ca)
+{
+    switch (ca.car) {
+    case 7:
+        //FIXME should beep
+        break;
+
+    case 8:
+        if (cp.x > 0)
+            cp.x--;
+        break;
+
+    case '\r':
+        cp.x = 0;
+        break;
+
+    case '\n':
+        cp.y++;
+        break;
+
+    case '\t':
+        do {
+            struct carattr dummyca = {' ', ca.attr, ca.use_attr};
+            vgafb_write_char(cp, dummyca);
+            cp.x++;
+            cp = check_scroll(cp);
+        } while (cp.x % 8);
+        break;
+
+    default:
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
+
+    return check_scroll(cp);
 }
 
 static void
-biosfn_set_video_mode(u8 mode)
-{                               // mode: Bit 7 is 1 if no clear screen
+write_string(struct cursorpos cp, u8 flag, u8 attr, u16 count,
+             u16 seg, u8 *offset_far)
+{
+    // if row=0xff special case : use current cursor position
+    if (cp.y == 0xff)
+        cp = get_cursor_pos(cp.page);
+
+    while (count-- != 0) {
+        u8 car = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+        if ((flag & 0x02) != 0) {
+            attr = GET_FARVAR(seg, *offset_far);
+            offset_far++;
+        }
+
+        struct carattr ca = {car, attr, 1};
+        cp = write_teletype(cp, ca);
+    }
+
+    if (flag & 0x01)
+        set_cursor_pos(cp);
+}
+
+static void
+set_scan_lines(u8 lines)
+{
+    vgahw_set_scan_lines(lines);
+    if (lines == 8)
+        biosfn_set_cursor_shape(0x06, 0x07);
+    else
+        biosfn_set_cursor_shape(lines - 4, lines - 3);
+    SET_BDA(char_height, lines);
+    u16 vde = vgahw_get_vde();
+    u8 rows = vde / lines;
+    SET_BDA(video_rows, rows - 1);
+    u16 cols = GET_BDA(video_cols);
+    SET_BDA(video_pagesize, rows * cols * 2);
+}
+
+static void
+biosfn_save_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
+    SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
+    SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
+    SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
+    SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
+    SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
+    SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
+    SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
+    SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
+    SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
+    u16 i;
+    for (i=0; i<8; i++)
+        SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
+    SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
+    SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
+    /* current font */
+    SET_FARVAR(seg, *(u32*)&info->font0_off, GET_IVT(0x1f).segoff);
+    SET_FARVAR(seg, *(u32*)&info->font1_off, GET_IVT(0x43).segoff);
+}
+
+static void
+biosfn_restore_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
+    SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
+    SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
+    SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
+    SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
+    SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
+    SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
+    SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
+    SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
+    SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
+    u16 i;
+    for (i = 0; i < 8; i++)
+        SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
+    SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
+    SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
+    /* current font */
+    SET_IVT(0x1f, GET_FARVAR(seg, info->font0_seg)
+            , GET_FARVAR(seg, info->font0_off));
+    SET_IVT(0x43, GET_FARVAR(seg, info->font1_seg)
+            , GET_FARVAR(seg, info->font1_off));
+}
+
+
+/****************************************************************
+ * VGA int 10 handler
+ ****************************************************************/
+
+// set video mode
+static void
+handle_1000(struct bregs *regs)
+{
+    u8 noclearmem = regs->al & 0x80;
+    u8 mode = regs->al & 0x7f;
+
+    // Set regs->al
+    if (mode > 7)
+        regs->al = 0x20;
+    else if (mode == 6)
+        regs->al = 0x3f;
+    else
+        regs->al = 0x30;
+
     if (CONFIG_CIRRUS)
         cirrus_set_video_mode(mode);
 
@@ -202,21 +351,12 @@ biosfn_set_video_mode(u8 mode)
         if (vbe_has_vbe_display())
             dispi_set_enable(VBE_DISPI_DISABLED);
 
-    // The real mode
-    u8 noclearmem = mode & 0x80;
-    mode = mode & 0x7f;
-
     // find the entry in the video modes
     struct vgamode_s *vmode_g = find_vga_entry(mode);
     dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
     if (!vmode_g)
         return;
 
-    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
-    u16 twidth = GET_GLOBAL(vparam_g->twidth);
-    u16 theightm1 = GET_GLOBAL(vparam_g->theightm1);
-    u16 cheight = GET_GLOBAL(vparam_g->cheight);
-
     // Read the bios mode set control
     u8 modeset_ctl = GET_BDA(modeset_ctl);
 
@@ -225,97 +365,42 @@ biosfn_set_video_mode(u8 mode)
 
     // if palette loading (bit 3 of modeset ctl = 0)
     if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
-        outb(GET_GLOBAL(vmode_g->pelmask), VGAREG_PEL_MASK);
-
-        // Set the whole dac always, from 0
-        outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
+        vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
 
         // From which palette
         u8 *palette_g = GET_GLOBAL(vmode_g->dac);
         u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
+
         // Always 256*3 values
+        vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
         u16 i;
-        for (i = 0; i < 0x0100; i++) {
-            if (i < palsize) {
-                outb(GET_GLOBAL(palette_g[(i * 3) + 0]), VGAREG_DAC_DATA);
-                outb(GET_GLOBAL(palette_g[(i * 3) + 1]), VGAREG_DAC_DATA);
-                outb(GET_GLOBAL(palette_g[(i * 3) + 2]), VGAREG_DAC_DATA);
-            } else {
-                outb(0, VGAREG_DAC_DATA);
-                outb(0, VGAREG_DAC_DATA);
-                outb(0, VGAREG_DAC_DATA);
-            }
+        for (i = palsize; i < 0x0100; i++) {
+            static u8 rgb[3] VAR16;
+            vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
         }
+
         if ((modeset_ctl & 0x02) == 0x02)
             biosfn_perform_gray_scale_summing(0x00, 0x100);
     }
-    // Reset Attribute Ctl flip-flop
-    inb(VGAREG_ACTL_RESET);
 
-    // Set Attribute Ctl
-    u16 i;
-    for (i = 0; i <= 0x13; i++) {
-        outb(i, VGAREG_ACTL_ADDRESS);
-        outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
-    }
-    outb(0x14, VGAREG_ACTL_ADDRESS);
-    outb(0x00, VGAREG_ACTL_WRITE_DATA);
-
-    // Set Sequencer Ctl
-    outb(0, VGAREG_SEQU_ADDRESS);
-    outb(0x03, VGAREG_SEQU_DATA);
-    for (i = 1; i <= 4; i++) {
-        outb(i, VGAREG_SEQU_ADDRESS);
-        outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
-    }
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    vgahw_set_mode(vparam_g);
 
-    // Set Grafx Ctl
-    for (i = 0; i <= 8; i++) {
-        outb(i, VGAREG_GRDC_ADDRESS);
-        outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
-    }
+    if (noclearmem == 0x00)
+        clear_screen(vmode_g);
 
     // Set CRTC address VGA or MDA
     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
     if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
 
-    // Disable CRTC write protection
-    outw(0x0011, crtc_addr);
-    // Set CRTC regs
-    for (i = 0; i <= 0x18; i++) {
-        outb(i, crtc_addr);
-        outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
-    }
-
-    // Set the misc register
-    outb(GET_GLOBAL(vparam_g->miscreg), VGAREG_WRITE_MISC_OUTPUT);
-
-    // Enable video
-    outb(0x20, VGAREG_ACTL_ADDRESS);
-    inb(VGAREG_ACTL_RESET);
-
-    if (noclearmem == 0x00) {
-        if (GET_GLOBAL(vmode_g->class) == TEXT) {
-            memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
-        } else {
-            if (mode < 0x0d) {
-                memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
-            } else {
-                outb(0x02, VGAREG_SEQU_ADDRESS);
-                u8 mmask = inb(VGAREG_SEQU_DATA);
-                outb(0x0f, VGAREG_SEQU_DATA);   // all planes
-                memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
-                outb(mmask, VGAREG_SEQU_DATA);
-            }
-        }
-    }
     // Set the BIOS mem
+    u16 cheight = GET_GLOBAL(vparam_g->cheight);
     SET_BDA(video_mode, mode);
-    SET_BDA(video_cols, twidth);
+    SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
     SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
     SET_BDA(crtc_address, crtc_addr);
-    SET_BDA(video_rows, theightm1);
+    SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
     SET_BDA(char_height, cheight);
     SET_BDA(video_ctl, (0x60 | noclearmem));
     SET_BDA(video_switches, 0xF9);
@@ -331,17 +416,20 @@ biosfn_set_video_mode(u8 mode)
     SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
 
     // Set cursor shape
-    if (GET_GLOBAL(vmode_g->class) == TEXT)
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
         biosfn_set_cursor_shape(0x06, 0x07);
     // Set cursor pos for page 0..7
-    for (i = 0; i < 8; i++)
-        biosfn_set_cursor_pos(i, 0x0000);
+    int i;
+    for (i = 0; i < 8; i++) {
+        struct cursorpos cp = {0, 0, i};
+        set_cursor_pos(cp);
+    }
 
     // Set active page 0
     biosfn_set_active_page(0x00);
 
     // Write the fonts in memory
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
         call16_vgaint(0x1104, 0);
         call16_vgaint(0x1103, 0);
     }
@@ -361,597 +449,6 @@ biosfn_set_video_mode(u8 mode)
     }
 }
 
-// -------------------------------------------------------------------
-static void
-biosfn_write_teletype(u8 car, u8 page, u8 attr, u8 flag)
-{                               // flag = WITH_ATTR / NO_ATTR
-    // special case if page is 0xff, use current page
-    if (page == 0xff)
-        page = GET_BDA(video_page);
-
-    // Get the mode
-    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
-    if (!vmode_g)
-        return;
-
-    // Get the cursor pos for the page
-    u16 cursor = biosfn_get_cursor_pos(page);
-    u8 xcurs = cursor & 0x00ff;
-    u8 ycurs = (cursor & 0xff00) >> 8;
-
-    // Get the dimensions
-    u16 nbrows = GET_BDA(video_rows) + 1;
-    u16 nbcols = GET_BDA(video_cols);
-
-    switch (car) {
-    case 7:
-        //FIXME should beep
-        break;
-
-    case 8:
-        if (xcurs > 0)
-            xcurs--;
-        break;
-
-    case '\r':
-        xcurs = 0;
-        break;
-
-    case '\n':
-        ycurs++;
-        break;
-
-    case '\t':
-        do {
-            biosfn_write_teletype(' ', page, attr, flag);
-            cursor = biosfn_get_cursor_pos(page);
-            xcurs = cursor & 0x00ff;
-            ycurs = (cursor & 0xff00) >> 8;
-        } while (xcurs % 8 == 0);
-        break;
-
-    default:
-        if (flag == WITH_ATTR)
-            biosfn_write_char_attr(car, page, attr, 1);
-        else
-            biosfn_write_char_only(car, page, attr, 1);
-        xcurs++;
-    }
-
-    // Do we need to wrap ?
-    if (xcurs == nbcols) {
-        xcurs = 0;
-        ycurs++;
-    }
-    // Do we need to scroll ?
-    if (ycurs == nbrows) {
-        if (GET_GLOBAL(vmode_g->class) == TEXT)
-            biosfn_scroll(0x01, 0x07, 0, 0, nbrows - 1, nbcols - 1, page,
-                          SCROLL_UP);
-        else
-            biosfn_scroll(0x01, 0x00, 0, 0, nbrows - 1, nbcols - 1, page,
-                          SCROLL_UP);
-        ycurs -= 1;
-    }
-    // Set the cursor for the page
-    cursor = ycurs;
-    cursor <<= 8;
-    cursor += xcurs;
-    biosfn_set_cursor_pos(page, cursor);
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_get_video_mode(struct bregs *regs)
-{
-    regs->bh = GET_BDA(video_page);
-    regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
-    regs->ah = GET_BDA(video_cols);
-}
-
-static void
-set_scan_lines(u8 lines)
-{
-    vgahw_set_scan_lines(lines);
-    if (lines == 8)
-        biosfn_set_cursor_shape(0x06, 0x07);
-    else
-        biosfn_set_cursor_shape(lines - 4, lines - 3);
-    SET_BDA(char_height, lines);
-    u16 vde = vgahw_get_vde();
-    u8 rows = vde / lines;
-    SET_BDA(video_rows, rows - 1);
-    u16 cols = GET_BDA(video_cols);
-    SET_BDA(video_pagesize, rows * cols * 2);
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_get_font_info(u8 BH, u16 *ES, u16 *BP, u16 *CX, u16 *DX)
-{
-    switch (BH) {
-    case 0x00: {
-        u32 segoff = GET_IVT(0x1f).segoff;
-        *ES = segoff >> 16;
-        *BP = segoff;
-        break;
-    }
-    case 0x01: {
-        u32 segoff = GET_IVT(0x43).segoff;
-        *ES = segoff >> 16;
-        *BP = segoff;
-        break;
-    }
-    case 0x02:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont14;
-        break;
-    case 0x03:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont8;
-        break;
-    case 0x04:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont8 + 128 * 8;
-        break;
-    case 0x05:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont14alt;
-        break;
-    case 0x06:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont16;
-        break;
-    case 0x07:
-        *ES = get_global_seg();
-        *BP = (u32)vgafont16alt;
-        break;
-    default:
-        dprintf(1, "Get font info BH(%02x) was discarded\n", BH);
-        return;
-    }
-    // Set byte/char of on screen font
-    *CX = GET_BDA(char_height) & 0xff;
-
-    // Set Highest char row
-    *DX = GET_BDA(video_rows);
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_get_ega_info(struct bregs *regs)
-{
-    regs->cx = GET_BDA(video_switches) & 0x0f;
-    regs->ax = GET_BDA(crtc_address);
-    if (regs->ax == VGAREG_MDA_CRTC_ADDRESS)
-        regs->bx = 0x0103;
-    else
-        regs->bx = 0x0003;
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_select_vert_res(struct bregs *regs)
-{
-    u8 mctl = GET_BDA(modeset_ctl);
-    u8 vswt = GET_BDA(video_switches);
-
-    switch (regs->al) {
-    case 0x00:
-        // 200 lines
-        mctl = (mctl & ~0x10) | 0x80;
-        vswt = (vswt & ~0x0f) | 0x08;
-        break;
-    case 0x01:
-        // 350 lines
-        mctl &= ~0x90;
-        vswt = (vswt & ~0x0f) | 0x09;
-        break;
-    case 0x02:
-        // 400 lines
-        mctl = (mctl & ~0x80) | 0x10;
-        vswt = (vswt & ~0x0f) | 0x09;
-        break;
-    default:
-        dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
-        break;
-    }
-    SET_BDA(modeset_ctl, mctl);
-    SET_BDA(video_switches, vswt);
-    regs->ax = 0x1212;
-}
-
-static void
-biosfn_enable_default_palette_loading(struct bregs *regs)
-{
-    u8 v = (regs->al & 0x01) << 3;
-    u8 mctl = GET_BDA(video_ctl) & ~0x08;
-    SET_BDA(video_ctl, mctl | v);
-    regs->ax = 0x1212;
-}
-
-
-static void
-biosfn_enable_grayscale_summing(struct bregs *regs)
-{
-    u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
-    u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
-    SET_BDA(modeset_ctl, v | v2);
-    regs->ax = 0x1212;
-}
-
-static void
-biosfn_enable_cursor_emulation(struct bregs *regs)
-{
-    u8 v = (regs->al & 0x01) ^ 0x01;
-    u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
-    SET_BDA(modeset_ctl, v | v2);
-    regs->ax = 0x1212;
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_write_string(u8 flag, u8 page, u8 attr, u16 count, u8 row, u8 col,
-                    u16 seg, u8 *offset_far)
-{
-    // Read curs info for the page
-    u16 oldcurs = biosfn_get_cursor_pos(page);
-
-    // if row=0xff special case : use current cursor position
-    if (row == 0xff) {
-        col = oldcurs & 0x00ff;
-        row = (oldcurs & 0xff00) >> 8;
-    }
-
-    u16 newcurs = row;
-    newcurs <<= 8;
-    newcurs += col;
-    biosfn_set_cursor_pos(page, newcurs);
-
-    while (count-- != 0) {
-        u8 car = GET_FARVAR(seg, *offset_far);
-        offset_far++;
-        if ((flag & 0x02) != 0) {
-            attr = GET_FARVAR(seg, *offset_far);
-            offset_far++;
-        }
-
-        biosfn_write_teletype(car, page, attr, WITH_ATTR);
-    }
-
-    // Set back curs pos
-    if ((flag & 0x01) == 0)
-        biosfn_set_cursor_pos(page, oldcurs);
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_read_display_code(struct bregs *regs)
-{
-    regs->bx = GET_BDA(dcc_index);
-    regs->al = 0x1a;
-}
-
-static void
-biosfn_set_display_code(struct bregs *regs)
-{
-    SET_BDA(dcc_index, regs->bl);
-    dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
-    regs->al = 0x1a;
-}
-
-// -------------------------------------------------------------------
-static void
-biosfn_read_state_info(u16 BX, u16 ES, u16 DI)
-{
-    // Address of static functionality table
-    SET_FARVAR(ES, *(u16*)(DI + 0x00), (u32)static_functionality);
-    SET_FARVAR(ES, *(u16*)(DI + 0x02), get_global_seg());
-
-    // Hard coded copy from BIOS area. Should it be cleaner ?
-    memcpy_far(ES, (void*)(DI + 0x04), SEG_BDA, (void*)0x49, 30);
-    memcpy_far(ES, (void*)(DI + 0x22), SEG_BDA, (void*)0x84, 3);
-
-    SET_FARVAR(ES, *(u8*)(DI + 0x25), GET_BDA(dcc_index));
-    SET_FARVAR(ES, *(u8*)(DI + 0x26), 0);
-    SET_FARVAR(ES, *(u8*)(DI + 0x27), 16);
-    SET_FARVAR(ES, *(u8*)(DI + 0x28), 0);
-    SET_FARVAR(ES, *(u8*)(DI + 0x29), 8);
-    SET_FARVAR(ES, *(u8*)(DI + 0x2a), 2);
-    SET_FARVAR(ES, *(u8*)(DI + 0x2b), 0);
-    SET_FARVAR(ES, *(u8*)(DI + 0x2c), 0);
-    SET_FARVAR(ES, *(u8*)(DI + 0x31), 3);
-    SET_FARVAR(ES, *(u8*)(DI + 0x32), 0);
-
-    memset_far(ES, (void*)(DI + 0x33), 0, 13);
-}
-
-// -------------------------------------------------------------------
-// -------------------------------------------------------------------
-static u16
-biosfn_read_video_state_size(u16 CX)
-{
-    u16 size = 0;
-    if (CX & 1)
-        size += 0x46;
-    if (CX & 2)
-        size += (5 + 8 + 5) * 2 + 6;
-    if (CX & 4)
-        size += 3 + 256 * 3 + 1;
-    return size;
-}
-
-static u16
-biosfn_save_video_state(u16 CX, u16 ES, u16 BX)
-{
-    u16 crtc_addr = GET_BDA(crtc_address);
-    if (CX & 1) {
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_ADDRESS));
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr));
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_ADDRESS));
-        BX++;
-        inb(VGAREG_ACTL_RESET);
-        u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
-        SET_FARVAR(ES, *(u8*)(BX+0), ar_index);
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_READ_FEATURE_CTL));
-        BX++;
-
-        u16 i;
-        for (i = 1; i <= 4; i++) {
-            outb(i, VGAREG_SEQU_ADDRESS);
-            SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
-            BX++;
-        }
-        outb(0, VGAREG_SEQU_ADDRESS);
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_SEQU_DATA));
-        BX++;
-
-        for (i = 0; i <= 0x18; i++) {
-            outb(i, crtc_addr);
-            SET_FARVAR(ES, *(u8*)(BX+0), inb(crtc_addr + 1));
-            BX++;
-        }
-
-        for (i = 0; i <= 0x13; i++) {
-            inb(VGAREG_ACTL_RESET);
-            outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
-            SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_ACTL_READ_DATA));
-            BX++;
-        }
-        inb(VGAREG_ACTL_RESET);
-
-        for (i = 0; i <= 8; i++) {
-            outb(i, VGAREG_GRDC_ADDRESS);
-            SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_GRDC_DATA));
-            BX++;
-        }
-
-        SET_FARVAR(ES, *(u16*)(BX+0), crtc_addr);
-        BX += 2;
-
-        /* XXX: read plane latches */
-        SET_FARVAR(ES, *(u8*)(BX+0), 0);
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), 0);
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), 0);
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), 0);
-        BX++;
-    }
-    if (CX & 2) {
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_mode));
-        BX++;
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_cols));
-        BX += 2;
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagesize));
-        BX += 2;
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(crtc_address));
-        BX += 2;
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_rows));
-        BX++;
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(char_height));
-        BX += 2;
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_ctl));
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_switches));
-        BX++;
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(modeset_ctl));
-        BX++;
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_type));
-        BX += 2;
-        u16 i;
-        for (i = 0; i < 8; i++) {
-            SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(cursor_pos[i]));
-            BX += 2;
-        }
-        SET_FARVAR(ES, *(u16*)(BX+0), GET_BDA(video_pagestart));
-        BX += 2;
-        SET_FARVAR(ES, *(u8*)(BX+0), GET_BDA(video_page));
-        BX++;
-        /* current font */
-        SET_FARVAR(ES, *(u32*)(BX+0), GET_IVT(0x1f).segoff);
-        BX += 4;
-        SET_FARVAR(ES, *(u32*)(BX+0), GET_IVT(0x43).segoff);
-        BX += 4;
-    }
-    if (CX & 4) {
-        /* XXX: check this */
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_STATE));
-        BX++;                   /* read/write mode dac */
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_WRITE_ADDRESS));
-        BX++;                   /* pix address */
-        SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_PEL_MASK));
-        BX++;
-        // Set the whole dac always, from 0
-        outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
-        u16 i;
-        for (i = 0; i < 256 * 3; i++) {
-            SET_FARVAR(ES, *(u8*)(BX+0), inb(VGAREG_DAC_DATA));
-            BX++;
-        }
-        SET_FARVAR(ES, *(u8*)(BX+0), 0);
-        BX++;                   /* color select register */
-    }
-    return BX;
-}
-
-static u16
-biosfn_restore_video_state(u16 CX, u16 ES, u16 BX)
-{
-    if (CX & 1) {
-        // Reset Attribute Ctl flip-flop
-        inb(VGAREG_ACTL_RESET);
-
-        u16 crtc_addr = GET_FARVAR(ES, *(u16*)(BX + 0x40));
-        u16 addr1 = BX;
-        BX += 5;
-
-        u16 i;
-        for (i = 1; i <= 4; i++) {
-            outb(i, VGAREG_SEQU_ADDRESS);
-            outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
-            BX++;
-        }
-        outb(0, VGAREG_SEQU_ADDRESS);
-        outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_SEQU_DATA);
-        BX++;
-
-        // Disable CRTC write protection
-        outw(0x0011, crtc_addr);
-        // Set CRTC regs
-        for (i = 0; i <= 0x18; i++) {
-            if (i != 0x11) {
-                outb(i, crtc_addr);
-                outb(GET_FARVAR(ES, *(u8*)(BX+0)), crtc_addr + 1);
-            }
-            BX++;
-        }
-        // select crtc base address
-        u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
-        if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
-            v |= 0x01;
-        outb(v, VGAREG_WRITE_MISC_OUTPUT);
-
-        // enable write protection if needed
-        outb(0x11, crtc_addr);
-        outb(GET_FARVAR(ES, *(u8*)(BX - 0x18 + 0x11)), crtc_addr + 1);
-
-        // Set Attribute Ctl
-        u16 ar_index = GET_FARVAR(ES, *(u8*)(addr1 + 0x03));
-        inb(VGAREG_ACTL_RESET);
-        for (i = 0; i <= 0x13; i++) {
-            outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
-            outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_ACTL_WRITE_DATA);
-            BX++;
-        }
-        outb(ar_index, VGAREG_ACTL_ADDRESS);
-        inb(VGAREG_ACTL_RESET);
-
-        for (i = 0; i <= 8; i++) {
-            outb(i, VGAREG_GRDC_ADDRESS);
-            outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_GRDC_DATA);
-            BX++;
-        }
-        BX += 2;                /* crtc_addr */
-        BX += 4;                /* plane latches */
-
-        outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_SEQU_ADDRESS);
-        addr1++;
-        outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr);
-        addr1++;
-        outb(GET_FARVAR(ES, *(u8*)(addr1+0)), VGAREG_GRDC_ADDRESS);
-        addr1++;
-        addr1++;
-        outb(GET_FARVAR(ES, *(u8*)(addr1+0)), crtc_addr - 0x4 + 0xa);
-        addr1++;
-    }
-    if (CX & 2) {
-        SET_BDA(video_mode, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        SET_BDA(video_cols, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        SET_BDA(video_pagesize, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        SET_BDA(crtc_address, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        SET_BDA(video_rows, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        SET_BDA(char_height, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        SET_BDA(video_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        SET_BDA(video_switches, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        SET_BDA(modeset_ctl, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        SET_BDA(cursor_type, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        u16 i;
-        for (i = 0; i < 8; i++) {
-            SET_BDA(cursor_pos[i], GET_FARVAR(ES, *(u16*)(BX+0)));
-            BX += 2;
-        }
-        SET_BDA(video_pagestart, GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 2;
-        SET_BDA(video_page, GET_FARVAR(ES, *(u8*)(BX+0)));
-        BX++;
-        /* current font */
-        SET_IVT(0x1f, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 4;
-        SET_IVT(0x43, GET_FARVAR(ES, *(u16*)(BX+2)), GET_FARVAR(ES, *(u16*)(BX+0)));
-        BX += 4;
-    }
-    if (CX & 4) {
-        BX++;
-        u16 v = GET_FARVAR(ES, *(u8*)(BX+0));
-        BX++;
-        outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_PEL_MASK);
-        BX++;
-        // Set the whole dac always, from 0
-        outb(0x00, VGAREG_DAC_WRITE_ADDRESS);
-        u16 i;
-        for (i = 0; i < 256 * 3; i++) {
-            outb(GET_FARVAR(ES, *(u8*)(BX+0)), VGAREG_DAC_DATA);
-            BX++;
-        }
-        BX++;
-        outb(v, VGAREG_DAC_WRITE_ADDRESS);
-    }
-    return BX;
-}
-
-
-/****************************************************************
- * VGA int 10 handler
- ****************************************************************/
-
-static void
-handle_1000(struct bregs *regs)
-{
-    // XXX - inline
-    biosfn_set_video_mode(regs->al);
-    switch(regs->al & 0x7F) {
-    case 6:
-        regs->al = 0x3F;
-        break;
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-    case 5:
-    case 7:
-        regs->al = 0x30;
-        break;
-    default:
-        regs->al = 0x20;
-    }
-}
-
 static void
 handle_1001(struct bregs *regs)
 {
@@ -961,14 +458,17 @@ handle_1001(struct bregs *regs)
 static void
 handle_1002(struct bregs *regs)
 {
-    biosfn_set_cursor_pos(regs->bh, regs->dx);
+    struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+    set_cursor_pos(cp);
 }
 
 static void
 handle_1003(struct bregs *regs)
 {
     regs->cx = biosfn_get_cursor_shape(regs->bh);
-    regs->dx = biosfn_get_cursor_pos(regs->bh);
+    struct cursorpos cp = get_cursor_pos(regs->bh);
+    regs->dl = cp.x;
+    regs->dh = cp.y;
 }
 
 // Read light pen pos (unimplemented)
@@ -985,39 +485,72 @@ handle_1005(struct bregs *regs)
     biosfn_set_active_page(regs->al);
 }
 
+static void
+verify_scroll(struct bregs *regs, int dir)
+{
+    u8 page = GET_BDA(video_page);
+    struct cursorpos ul = {regs->cl, regs->ch, page};
+    struct cursorpos lr = {regs->dl, regs->dh, page};
+
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    if (lr.y >= nbrows)
+        lr.y = nbrows - 1;
+    u16 nbcols = GET_BDA(video_cols);
+    if (lr.x >= nbcols)
+        lr.x = nbcols - 1;
+
+    if (ul.x > lr.x || ul.y > lr.y)
+        return;
+
+    u16 nblines = regs->al;
+    if (!nblines || nblines > lr.y - ul.y + 1)
+        nblines = lr.y - ul.y + 1;
+
+    vgafb_scroll(dir * nblines, regs->bh, ul, lr);
+}
+
 static void
 handle_1006(struct bregs *regs)
 {
-    biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
-                  , 0xFF, SCROLL_UP);
+    verify_scroll(regs, 1);
 }
 
 static void
 handle_1007(struct bregs *regs)
 {
-    biosfn_scroll(regs->al, regs->bh, regs->ch, regs->cl, regs->dh, regs->dl
-                  , 0xFF, SCROLL_DOWN);
+    verify_scroll(regs, -1);
 }
 
 static void
 handle_1008(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_read_char_attr(regs->bh, &regs->ax);
+    struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
+    regs->al = ca.car;
+    regs->ah = ca.attr;
+}
+
+static void
+write_chars(u8 page, struct carattr ca, u16 count)
+{
+    struct cursorpos cp = get_cursor_pos(page);
+    while (count--) {
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
 }
 
 static void
 handle_1009(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_write_char_attr(regs->al, regs->bh, regs->bl, regs->cx);
+    struct carattr ca = {regs->al, regs->bl, 1};
+    write_chars(regs->bh, ca, regs->cx);
 }
 
 static void
 handle_100a(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_write_char_only(regs->al, regs->bh, regs->bl, regs->cx);
+    struct carattr ca = {regs->al, regs->bl, 0};
+    write_chars(regs->bh, ca, regs->cx);
 }
 
 
@@ -1069,14 +602,18 @@ handle_100e(struct bregs *regs)
 {
     // Ralf Brown Interrupt list is WRONG on bh(page)
     // We do output only on the current page !
-    biosfn_write_teletype(regs->al, 0xff, regs->bl, NO_ATTR);
+    struct carattr ca = {regs->al, regs->bl, 0};
+    struct cursorpos cp = get_cursor_pos(0xff);
+    cp = write_teletype(cp, ca);
+    set_cursor_pos(cp);
 }
 
 static void
 handle_100f(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_get_video_mode(regs);
+    regs->bh = GET_BDA(video_page);
+    regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
+    regs->ah = GET_BDA(video_cols);
 }
 
 
@@ -1219,20 +756,20 @@ handle_1010(struct bregs *regs)
 static void
 handle_101100(struct bregs *regs)
 {
-    biosfn_load_text_user_pat(regs->es, regs->bp
-                              , regs->cx, regs->dx, regs->bl, regs->bh);
+    vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+                    , regs->dx, regs->bl, regs->bh);
 }
 
 static void
 handle_101101(struct bregs *regs)
 {
-    biosfn_load_text_8_14_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
 }
 
 static void
 handle_101102(struct bregs *regs)
 {
-    biosfn_load_text_8_8_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
 }
 
 static void
@@ -1244,44 +781,87 @@ handle_101103(struct bregs *regs)
 static void
 handle_101104(struct bregs *regs)
 {
-    biosfn_load_text_8_16_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
 }
 
 static void
 handle_101110(struct bregs *regs)
 {
-    biosfn_load_text_user_pat(regs->es, regs->bp
-                              , regs->cx, regs->dx, regs->bl, regs->bh);
+    vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+                    , regs->dx, regs->bl, regs->bh);
     set_scan_lines(regs->bh);
 }
 
 static void
 handle_101111(struct bregs *regs)
 {
-    biosfn_load_text_8_14_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
     set_scan_lines(14);
 }
 
 static void
 handle_101112(struct bregs *regs)
 {
-    biosfn_load_text_8_8_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
     set_scan_lines(8);
 }
 
 static void
 handle_101114(struct bregs *regs)
 {
-    biosfn_load_text_8_16_pat(regs->bl);
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
     set_scan_lines(16);
 }
 
 static void
 handle_101130(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_get_font_info(regs->bh, &regs->es, &regs->bp
-                         , &regs->cx, &regs->dx);
+    switch (regs->bh) {
+    case 0x00: {
+        u32 segoff = GET_IVT(0x1f).segoff;
+        regs->es = segoff >> 16;
+        regs->bp = segoff;
+        break;
+    }
+    case 0x01: {
+        u32 segoff = GET_IVT(0x43).segoff;
+        regs->es = segoff >> 16;
+        regs->bp = segoff;
+        break;
+    }
+    case 0x02:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont14;
+        break;
+    case 0x03:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont8;
+        break;
+    case 0x04:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont8 + 128 * 8;
+        break;
+    case 0x05:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont14alt;
+        break;
+    case 0x06:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont16;
+        break;
+    case 0x07:
+        regs->es = get_global_seg();
+        regs->bp = (u32)vgafont16alt;
+        break;
+    default:
+        dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
+        return;
+    }
+    // Set byte/char of on screen font
+    regs->cx = GET_BDA(char_height) & 0xff;
+
+    // Set Highest char row
+    regs->dx = GET_BDA(video_rows);
 }
 
 static void
@@ -1312,22 +892,51 @@ handle_1011(struct bregs *regs)
 static void
 handle_101210(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_get_ega_info(regs);
+    u16 crtc_addr = GET_BDA(crtc_address);
+    if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
+        regs->bx = 0x0103;
+    else
+        regs->bx = 0x0003;
+    regs->cx = GET_BDA(video_switches) & 0x0f;
 }
 
 static void
 handle_101230(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_select_vert_res(regs);
+    u8 mctl = GET_BDA(modeset_ctl);
+    u8 vswt = GET_BDA(video_switches);
+    switch (regs->al) {
+    case 0x00:
+        // 200 lines
+        mctl = (mctl & ~0x10) | 0x80;
+        vswt = (vswt & ~0x0f) | 0x08;
+        break;
+    case 0x01:
+        // 350 lines
+        mctl &= ~0x90;
+        vswt = (vswt & ~0x0f) | 0x09;
+        break;
+    case 0x02:
+        // 400 lines
+        mctl = (mctl & ~0x80) | 0x10;
+        vswt = (vswt & ~0x0f) | 0x09;
+        break;
+    default:
+        dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
+        break;
+    }
+    SET_BDA(modeset_ctl, mctl);
+    SET_BDA(video_switches, vswt);
+    regs->al = 0x12;
 }
 
 static void
 handle_101231(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_enable_default_palette_loading(regs);
+    u8 v = (regs->al & 0x01) << 3;
+    u8 mctl = GET_BDA(video_ctl) & ~0x08;
+    SET_BDA(video_ctl, mctl | v);
+    regs->al = 0x12;
 }
 
 static void
@@ -1340,15 +949,19 @@ handle_101232(struct bregs *regs)
 static void
 handle_101233(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_enable_grayscale_summing(regs);
+    u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
+    u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
+    SET_BDA(modeset_ctl, v | v2);
+    regs->al = 0x12;
 }
 
 static void
 handle_101234(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_enable_cursor_emulation(regs);
+    u8 v = (regs->al & 0x01) ^ 0x01;
+    u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
+    SET_BDA(modeset_ctl, v | v2);
+    regs->al = 0x12;
 }
 
 static void
@@ -1394,23 +1007,25 @@ static void
 handle_1013(struct bregs *regs)
 {
     // XXX - inline
-    biosfn_write_string(regs->al, regs->bh, regs->bl, regs->cx
-                        , regs->dh, regs->dl, regs->es, (void*)(regs->bp + 0));
+    struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+    write_string(cp, regs->al, regs->bl, regs->cx
+                 , regs->es, (void*)(regs->bp + 0));
 }
 
 
 static void
 handle_101a00(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_read_display_code(regs);
+    regs->bx = GET_BDA(dcc_index);
+    regs->al = 0x1a;
 }
 
 static void
 handle_101a01(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_set_display_code(regs);
+    SET_BDA(dcc_index, regs->bl);
+    dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
+    regs->al = 0x1a;
 }
 
 static void
@@ -1430,11 +1045,46 @@ handle_101a(struct bregs *regs)
 }
 
 
+struct funcInfo {
+    u16 static_functionality_off;
+    u16 static_functionality_seg;
+    u8 bda_0x49[30];
+    u8 bda_0x84[3];
+    u8 dcc_index;
+    u8 dcc_alt;
+    u16 colors;
+    u8 pages;
+    u8 scan_lines;
+    u8 primary_char;
+    u8 secondar_char;
+    u8 misc;
+    u8 non_vga_mode;
+    u8 reserved_2f[2];
+    u8 video_mem;
+    u8 save_flags;
+    u8 disp_info;
+    u8 reserved_34[12];
+};
+
 static void
 handle_101b(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_read_state_info(regs->bx, regs->es, regs->di);
+    u16 seg = regs->es;
+    struct funcInfo *info = (void*)(regs->di+0);
+    memset_far(seg, info, 0, sizeof(*info));
+    // Address of static functionality table
+    SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
+    SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
+
+    // Hard coded copy from BIOS area. Should it be cleaner ?
+    memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49, 30);
+    memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84, 3);
+
+    SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
+    SET_FARVAR(seg, info->colors, 16);
+    SET_FARVAR(seg, info->pages, 8);
+    SET_FARVAR(seg, info->scan_lines, 2);
+    SET_FARVAR(seg, info->video_mem, 3);
     regs->al = 0x1B;
 }
 
@@ -1442,22 +1092,54 @@ handle_101b(struct bregs *regs)
 static void
 handle_101c00(struct bregs *regs)
 {
-    // XXX - inline
-    regs->bx = biosfn_read_video_state_size(regs->cx);
+    u16 flags = regs->cx;
+    u16 size = 0;
+    if (flags & 1)
+        size += sizeof(struct saveVideoHardware);
+    if (flags & 2)
+        size += sizeof(struct saveBDAstate);
+    if (flags & 4)
+        size += sizeof(struct saveDACcolors);
+    regs->bx = size;
+    regs->al = 0x1c;
 }
 
 static void
 handle_101c01(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_save_video_state(regs->cx, regs->es, regs->bx);
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_save_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        biosfn_save_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_save_dac_state(seg, data);
+    regs->al = 0x1c;
 }
 
 static void
 handle_101c02(struct bregs *regs)
 {
-    // XXX - inline
-    biosfn_restore_video_state(regs->cx, regs->es, regs->bx);
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_restore_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        biosfn_restore_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_restore_dac_state(seg, data);
+    regs->al = 0x1c;
 }
 
 static void