vgabios: Use vgamode_s instead of video_param_table in code.
[seabios.git] / vgasrc / vgafb.c
index 6e107023f591965742fa634be0e372be237b013a..1e1943dc2b6cb126b885a29c33d0f2ff1dbd5969 100644 (file)
 #include "util.h" // memset_far
 #include "vgatables.h" // find_vga_entry
 
-// XXX
-inline void
-memcpy16_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
-{
-    memcpy_far(d_seg, d_far, s_seg, s_far, len);
-}
-
 
 /****************************************************************
  * Screen scrolling
  ****************************************************************/
 
-static void
-vgamem_copy_pl4(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
-                u8 cheight)
+static inline void *
+memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
 {
-    u16 src = ysrc * cheight * nbcols + xstart;
-    u16 dest = ydest * cheight * nbcols + xstart;
-    outw(0x0105, VGAREG_GRDC_ADDRESS);
-    u8 i;
-    for (i = 0; i < cheight; i++)
-        memcpy_far(SEG_GRAPH, (void*)(dest + i * nbcols)
-                   , SEG_GRAPH, (void*)(src + i * nbcols), cols);
-    outw(0x0005, VGAREG_GRDC_ADDRESS);
+    for (; lines; lines--, dst+=stride, src+=stride)
+        memcpy_far(seg, dst, seg, src, copylen);
+    return dst;
 }
 
-static void
-vgamem_fill_pl4(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
-                u8 attr)
+static inline void
+memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
 {
-    u16 dest = ystart * cheight * nbcols + xstart;
-    outw(0x0205, VGAREG_GRDC_ADDRESS);
-    u8 i;
-    for (i = 0; i < cheight; i++)
-        memset_far(SEG_GRAPH, (void*)(dest + i * nbcols), attr, cols);
-    outw(0x0005, VGAREG_GRDC_ADDRESS);
+    for (; lines; lines--, dst+=stride)
+        memset_far(seg, dst, val, setlen);
 }
 
-static void
-vgamem_copy_cga(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
-                u8 cheight)
+static inline void
+memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
 {
-    u16 src = ((ysrc * cheight * nbcols) >> 1) + xstart;
-    u16 dest = ((ydest * cheight * nbcols) >> 1) + xstart;
-    u8 i;
-    for (i = 0; i < cheight; i++)
-        if (i & 1)
-            memcpy_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
-                       , SEG_CTEXT, (void*)(0x2000 + src + (i >> 1) * nbcols)
-                       , cols);
-        else
-            memcpy_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols)
-                       , SEG_CTEXT, (void*)(src + (i >> 1) * nbcols), cols);
+    for (; lines; lines--, dst+=stride)
+        memset16_far(seg, dst, val, setlen);
 }
 
 static void
-vgamem_fill_cga(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
-                u8 attr)
+scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
+           , struct cursorpos ul, struct cursorpos lr)
 {
-    u16 dest = ((ystart * cheight * nbcols) >> 1) + xstart;
-    u8 i;
-    for (i = 0; i < cheight; i++)
-        if (i & 1)
-            memset_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
-                       , attr, cols);
-        else
-            memset_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols), attr, cols);
+    u8 cheight = GET_GLOBAL(vmode_g->cheight);
+    int stride = GET_BDA(video_cols);
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
+    }
+    int cols = lr.x - ul.x + 1;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        vgahw_grdc_write(0x05, 0x01);
+        dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
+                                 , (rows - nblines) * cheight);
+    }
+    if (attr < 0)
+        attr = 0;
+    vgahw_grdc_write(0x05, 0x02);
+    memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
+    vgahw_grdc_write(0x05, 0x00);
 }
 
-void
-clear_screen(struct vgamode_s *vmode_g)
+static void
+scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
 {
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
-        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
-        return;
+    u8 cheight = GET_GLOBAL(vmode_g->cheight);
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    int stride = GET_BDA(video_cols) * bpp;
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
     }
-    if (GET_GLOBAL(vmode_g->svgamode) < 0x0d) {
-        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
-        return;
+    int cols = (lr.x - ul.x + 1) * bpp;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
+                      , stride, (rows - nblines) * cheight / 2);
+        dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
+                                 , stride, (rows - nblines) * cheight / 2);
     }
-    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);
+    if (attr < 0)
+        attr = 0;
+    memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
+                  , stride, nblines * cheight / 2);
+    memset_stride(SEG_CTEXT, dest_far, attr, cols
+                  , stride, nblines * cheight / 2);
 }
 
-void
-biosfn_scroll(u8 nblines, u8 attr, u8 rul, u8 cul, u8 rlr, u8 clr, u8 page,
-              u8 dir)
+static void
+scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
 {
-    // page == 0xFF if current
-    if (rul > rlr)
-        return;
-    if (cul > clr)
-        return;
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+    void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
+    int stride = nbcols * 2;
+    if (nblines >= 0) {
+        dest_far += ul.y * stride + ul.x * 2;
+        src_far = dest_far + nblines * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far += lr.y * stride + ul.x * 2;
+        src_far = dest_far - nblines * stride;
+        stride = -stride;
+    }
+    int cols = (lr.x - ul.x + 1) * 2;
+    int rows = lr.y - ul.y + 1;
+    u16 seg = GET_GLOBAL(vmode_g->sstart);
+    if (nblines < rows)
+        dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
+                                 , (rows - nblines));
+    if (attr < 0)
+        attr = 0x07;
+    attr = (attr << 8) | ' ';
+    memset16_stride(seg, dest_far, attr, cols, stride, nblines);
+}
 
+void
+vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
+{
     // Get the mode
     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
     if (!vmode_g)
         return;
 
-    // Get the dimensions
-    u16 nbrows = GET_BDA(video_rows) + 1;
-    u16 nbcols = GET_BDA(video_cols);
-
-    // Get the current page
-    if (page == 0xFF)
-        page = GET_BDA(video_page);
-
-    if (rlr >= nbrows)
-        rlr = nbrows - 1;
-    if (clr >= nbcols)
-        clr = nbcols - 1;
-    if (nblines > nbrows)
-        nblines = 0;
-    u8 cols = clr - cul + 1;
-
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
-        // Compute the address
-        void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page));
-        dprintf(3, "Scroll, address %p (%d %d %02x)\n"
-                , address_far, nbrows, nbcols, page);
-
-        if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
-            && clr == nbcols - 1) {
-            memset16_far(GET_GLOBAL(vmode_g->sstart), address_far
-                         , (u16)attr * 0x100 + ' ', nbrows * nbcols * 2);
-        } else {                // if Scroll up
-            if (dir == SCROLL_UP) {
-                u16 i;
-                for (i = rul; i <= rlr; i++)
-                    if ((i + nblines > rlr) || (nblines == 0))
-                        memset16_far(GET_GLOBAL(vmode_g->sstart)
-                                     , address_far + (i * nbcols + cul) * 2
-                                     , (u16)attr * 0x100 + ' ', cols * 2);
-                    else
-                        memcpy16_far(GET_GLOBAL(vmode_g->sstart)
-                                     , address_far + (i * nbcols + cul) * 2
-                                     , GET_GLOBAL(vmode_g->sstart)
-                                     , (void*)(((i + nblines) * nbcols + cul) * 2)
-                                     , cols * 2);
-            } else {
-                u16 i;
-                for (i = rlr; i >= rul; i--) {
-                    if ((i < rul + nblines) || (nblines == 0))
-                        memset16_far(GET_GLOBAL(vmode_g->sstart)
-                                     , address_far + (i * nbcols + cul) * 2
-                                     , (u16)attr * 0x100 + ' ', cols * 2);
-                    else
-                        memcpy16_far(GET_GLOBAL(vmode_g->sstart)
-                                     , address_far + (i * nbcols + cul) * 2
-                                     , GET_GLOBAL(vmode_g->sstart)
-                                     , (void*)(((i - nblines) * nbcols + cul) * 2)
-                                     , cols * 2);
-                    if (i > rlr)
-                        break;
-                }
-            }
-        }
-        return;
-    }
-
     // FIXME gfx mode not complete
-    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
-    u8 cheight = GET_GLOBAL(vparam_g->cheight);
     switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        scroll_text(vmode_g, nblines, attr, ul, lr);
+        break;
     case PLANAR4:
     case PLANAR1:
-        if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
-            && clr == nbcols - 1) {
-            outw(0x0205, VGAREG_GRDC_ADDRESS);
-            memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
-                       nbrows * nbcols * cheight);
-            outw(0x0005, VGAREG_GRDC_ADDRESS);
-        } else {            // if Scroll up
-            if (dir == SCROLL_UP) {
-                u16 i;
-                for (i = rul; i <= rlr; i++)
-                    if ((i + nblines > rlr) || (nblines == 0))
-                        vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
-                                        attr);
-                    else
-                        vgamem_copy_pl4(cul, i + nblines, i, cols,
-                                        nbcols, cheight);
-            } else {
-                u16 i;
-                for (i = rlr; i >= rul; i--) {
-                    if ((i < rul + nblines) || (nblines == 0))
-                        vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
-                                        attr);
-                    else
-                        vgamem_copy_pl4(cul, i, i - nblines, cols,
-                                        nbcols, cheight);
-                    if (i > rlr)
-                        break;
-                }
-            }
-        }
+        scroll_pl4(vmode_g, nblines, attr, ul, lr);
         break;
-    case CGA: {
-        u8 bpp = GET_GLOBAL(vmode_g->pixbits);
-        if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
-            && clr == nbcols - 1) {
-            memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
-                       nbrows * nbcols * cheight * bpp);
-        } else {
-            if (bpp == 2) {
-                cul <<= 1;
-                cols <<= 1;
-                nbcols <<= 1;
-            }
-            // if Scroll up
-            if (dir == SCROLL_UP) {
-                u16 i;
-                for (i = rul; i <= rlr; i++)
-                    if ((i + nblines > rlr) || (nblines == 0))
-                        vgamem_fill_cga(cul, i, cols, nbcols, cheight,
-                                        attr);
-                    else
-                        vgamem_copy_cga(cul, i + nblines, i, cols,
-                                        nbcols, cheight);
-            } else {
-                u16 i;
-                for (i = rlr; i >= rul; i--) {
-                    if ((i < rul + nblines) || (nblines == 0))
-                        vgamem_fill_cga(cul, i, cols, nbcols, cheight,
-                                        attr);
-                    else
-                        vgamem_copy_cga(cul, i, i - nblines, cols,
-                                        nbcols, cheight);
-                    if (i > rlr)
-                        break;
-                }
-            }
-        }
+    case CGA:
+        scroll_cga(vmode_g, nblines, attr, ul, lr);
         break;
-    }
     default:
         dprintf(1, "Scroll in graphics mode\n");
     }
 }
 
+void
+clear_screen(struct vgamode_s *vmode_g)
+{
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+        break;
+    case 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);
+    }
+}
+
 
 /****************************************************************
  * Read/write characters to screen
  ****************************************************************/
 
 static void
-write_gfx_char_pl4(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols,
-                   u8 cheight)
+write_gfx_char_pl4(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
 {
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    u8 cheight = GET_GLOBAL(vmode_g->cheight);
     u8 *fdata_g;
     switch (cheight) {
     case 14:
@@ -272,39 +200,45 @@ write_gfx_char_pl4(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols,
     default:
         fdata_g = vgafont8;
     }
-    u16 addr = xcurs + ycurs * cheight * nbcols;
-    u16 src = car * cheight;
-    outw(0x0f02, VGAREG_SEQU_ADDRESS);
-    outw(0x0205, VGAREG_GRDC_ADDRESS);
-    if (attr & 0x80)
-        outw(0x1803, VGAREG_GRDC_ADDRESS);
+    u16 addr = cp.x + cp.y * cheight * nbcols;
+    u16 src = ca.car * cheight;
+    vgahw_sequ_write(0x02, 0x0f);
+    vgahw_grdc_write(0x05, 0x02);
+    if (ca.attr & 0x80)
+        vgahw_grdc_write(0x03, 0x18);
     else
-        outw(0x0003, VGAREG_GRDC_ADDRESS);
+        vgahw_grdc_write(0x03, 0x00);
     u8 i;
     for (i = 0; i < cheight; i++) {
         u8 *dest_far = (void*)(addr + i * nbcols);
         u8 j;
         for (j = 0; j < 8; j++) {
             u8 mask = 0x80 >> j;
-            outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
+            vgahw_grdc_write(0x08, mask);
             GET_FARVAR(SEG_GRAPH, *dest_far);
             if (GET_GLOBAL(fdata_g[src + i]) & mask)
-                SET_FARVAR(SEG_GRAPH, *dest_far, attr & 0x0f);
+                SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
             else
                 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
         }
     }
-    outw(0xff08, VGAREG_GRDC_ADDRESS);
-    outw(0x0005, VGAREG_GRDC_ADDRESS);
-    outw(0x0003, VGAREG_GRDC_ADDRESS);
+    vgahw_grdc_write(0x08, 0xff);
+    vgahw_grdc_write(0x05, 0x00);
+    vgahw_grdc_write(0x03, 0x00);
 }
 
 static void
-write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
+write_gfx_char_cga(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
 {
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
     u8 *fdata_g = vgafont8;
-    u16 addr = (xcurs * bpp) + ycurs * 320;
-    u16 src = car * 8;
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    u16 addr = (cp.x * bpp) + cp.y * 320;
+    u16 src = ca.car * 8;
     u8 i;
     for (i = 0; i < 8; i++) {
         u8 *dest_far = (void*)(addr + (i >> 1) * 80);
@@ -313,15 +247,15 @@ write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
         u8 mask = 0x80;
         if (bpp == 1) {
             u8 data = 0;
-            if (attr & 0x80)
+            if (ca.attr & 0x80)
                 data = GET_FARVAR(SEG_CTEXT, *dest_far);
             u8 j;
             for (j = 0; j < 8; j++) {
                 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
-                    if (attr & 0x80)
-                        data ^= (attr & 0x01) << (7 - j);
+                    if (ca.attr & 0x80)
+                        data ^= (ca.attr & 0x01) << (7 - j);
                     else
-                        data |= (attr & 0x01) << (7 - j);
+                        data |= (ca.attr & 0x01) << (7 - j);
                 }
                 mask >>= 1;
             }
@@ -329,15 +263,15 @@ write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
         } else {
             while (mask > 0) {
                 u8 data = 0;
-                if (attr & 0x80)
+                if (ca.attr & 0x80)
                     data = GET_FARVAR(SEG_CTEXT, *dest_far);
                 u8 j;
                 for (j = 0; j < 4; j++) {
                     if (GET_GLOBAL(fdata_g[src + i]) & mask) {
-                        if (attr & 0x80)
-                            data ^= (attr & 0x03) << ((3 - j) * 2);
+                        if (ca.attr & 0x80)
+                            data ^= (ca.attr & 0x03) << ((3 - j) * 2);
                         else
-                            data |= (attr & 0x03) << ((3 - j) * 2);
+                            data |= (ca.attr & 0x03) << ((3 - j) * 2);
                     }
                     mask >>= 1;
                 }
@@ -349,11 +283,17 @@ write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
 }
 
 static void
-write_gfx_char_lin(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols)
+write_gfx_char_lin(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
 {
+    // Get the dimensions
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
     u8 *fdata_g = vgafont8;
-    u16 addr = xcurs * 8 + ycurs * nbcols * 64;
-    u16 src = car * 8;
+    u16 addr = cp.x * 8 + cp.y * nbcols * 64;
+    u16 src = ca.car * 8;
     u8 i;
     for (i = 0; i < 8; i++) {
         u8 *dest_far = (void*)(addr + i * nbcols * 8);
@@ -362,137 +302,88 @@ write_gfx_char_lin(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols)
         for (j = 0; j < 8; j++) {
             u8 data = 0x00;
             if (GET_GLOBAL(fdata_g[src + i]) & mask)
-                data = attr;
+                data = ca.attr;
             SET_FARVAR(SEG_GRAPH, dest_far[j], data);
             mask >>= 1;
         }
     }
 }
 
-void
-biosfn_write_char_attr(u8 car, u8 page, u8 attr, u16 count)
+static void
+write_text_char(struct vgamode_s *vmode_g
+                , struct cursorpos cp, struct carattr ca)
 {
-    // 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);
 
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
-        // Compute the address
-        void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
-                                    + (xcurs + ycurs * nbcols) * 2);
+    // Compute the address
+    void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                                + (cp.x + cp.y * nbcols) * 2);
 
-        u16 dummy = ((u16)attr << 8) + car;
-        memset16_far(GET_GLOBAL(vmode_g->sstart), address_far, dummy, count * 2);
-        return;
-    }
-
-    // FIXME gfx mode not complete
-    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
-    u8 cheight = GET_GLOBAL(vparam_g->cheight);
-    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
-    while ((count-- > 0) && (xcurs < nbcols)) {
-        switch (GET_GLOBAL(vmode_g->memmodel)) {
-        case PLANAR4:
-        case PLANAR1:
-            write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
-            break;
-        case CGA:
-            write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
-            break;
-        case LINEAR8:
-            write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
-            break;
-        }
-        xcurs++;
+    if (ca.use_attr) {
+        u16 dummy = (ca.attr << 8) | ca.car;
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
+    } else {
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
     }
 }
 
 void
-biosfn_write_char_only(u8 car, u8 page, u8 attr, u16 count)
+vgafb_write_char(struct cursorpos cp, struct carattr ca)
 {
     // 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);
-
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
-        // Compute the address
-        u8 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
-                                  + (xcurs + ycurs * nbcols) * 2);
-        while (count-- > 0) {
-            SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far, car);
-            address_far += 2;
-        }
-        return;
-    }
-
     // FIXME gfx mode not complete
-    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
-    u8 cheight = GET_GLOBAL(vparam_g->cheight);
-    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
-    while ((count-- > 0) && (xcurs < nbcols)) {
-        switch (GET_GLOBAL(vmode_g->memmodel)) {
-        case PLANAR4:
-        case PLANAR1:
-            write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
-            break;
-        case CGA:
-            write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
-            break;
-        case LINEAR8:
-            write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
-            break;
-        }
-        xcurs++;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        write_text_char(vmode_g, cp, ca);
+        break;
+    case PLANAR4:
+    case PLANAR1:
+        write_gfx_char_pl4(vmode_g, cp, ca);
+        break;
+    case CGA:
+        write_gfx_char_cga(vmode_g, cp, ca);
+        break;
+    case LINEAR8:
+        write_gfx_char_lin(vmode_g, cp, ca);
+        break;
     }
 }
 
-void
-biosfn_read_char_attr(u8 page, u16 *car)
+struct carattr
+vgafb_read_char(struct cursorpos cp)
 {
     // Get the mode
     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
     if (!vmode_g)
-        return;
+        goto fail;
 
-    // Get the cursor pos for the page
-    u16 cursor = biosfn_get_cursor_pos(page);
-    u8 xcurs = cursor & 0x00ff;
-    u8 ycurs = (cursor & 0xff00) >> 8;
+    if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
+        // FIXME gfx mode
+        dprintf(1, "Read char in graphics mode\n");
+        goto fail;
+    }
 
     // Get the dimensions
     u16 nbrows = GET_BDA(video_rows) + 1;
     u16 nbcols = GET_BDA(video_cols);
 
-    if (GET_GLOBAL(vmode_g->class) == TEXT) {
-        // Compute the address
-        u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
-                                   + (xcurs + ycurs * nbcols) * 2);
+    // Compute the address
+    u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                               + (cp.x + cp.y * nbcols) * 2);
+    u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
+    struct carattr ca = {v, v>>8, 0};
+    return ca;
 
-        *car = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
-    } else {
-        // FIXME gfx mode
-        dprintf(1, "Read char in graphics mode\n");
-    }
+fail: ;
+    struct carattr ca2 = {0, 0, 0};
+    return ca2;
 }
 
 
@@ -501,47 +392,47 @@ biosfn_read_char_attr(u8 page, u16 *car)
  ****************************************************************/
 
 void
-biosfn_write_pixel(u8 BH, u8 AL, u16 CX, u16 DX)
+vgafb_write_pixel(u8 color, u16 x, u16 y)
 {
     // Get the mode
     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
     if (!vmode_g)
         return;
-    if (GET_GLOBAL(vmode_g->class) == TEXT)
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
         return;
 
     u8 *addr_far, mask, attr, data;
     switch (GET_GLOBAL(vmode_g->memmodel)) {
     case PLANAR4:
     case PLANAR1:
-        addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
-        mask = 0x80 >> (CX & 0x07);
-        outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
-        outw(0x0205, VGAREG_GRDC_ADDRESS);
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
+        vgahw_grdc_write(0x08, mask);
+        vgahw_grdc_write(0x05, 0x02);
         data = GET_FARVAR(SEG_GRAPH, *addr_far);
-        if (AL & 0x80)
-            outw(0x1803, VGAREG_GRDC_ADDRESS);
-        SET_FARVAR(SEG_GRAPH, *addr_far, AL);
-        outw(0xff08, VGAREG_GRDC_ADDRESS);
-        outw(0x0005, VGAREG_GRDC_ADDRESS);
-        outw(0x0003, VGAREG_GRDC_ADDRESS);
+        if (color & 0x80)
+            vgahw_grdc_write(0x03, 0x18);
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
+        vgahw_grdc_write(0x08, 0xff);
+        vgahw_grdc_write(0x05, 0x00);
+        vgahw_grdc_write(0x03, 0x00);
         break;
     case CGA:
         if (GET_GLOBAL(vmode_g->pixbits) == 2)
-            addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
+            addr_far = (void*)((x >> 2) + (y >> 1) * 80);
         else
-            addr_far = (void*)((CX >> 3) + (DX >> 1) * 80);
-        if (DX & 1)
+            addr_far = (void*)((x >> 3) + (y >> 1) * 80);
+        if (y & 1)
             addr_far += 0x2000;
         data = GET_FARVAR(SEG_CTEXT, *addr_far);
         if (GET_GLOBAL(vmode_g->pixbits) == 2) {
-            attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
-            mask = 0x03 << ((3 - (CX & 0x03)) * 2);
+            attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
+            mask = 0x03 << ((3 - (x & 0x03)) * 2);
         } else {
-            attr = (AL & 0x01) << (7 - (CX & 0x07));
-            mask = 0x01 << (7 - (CX & 0x07));
+            attr = (color & 0x01) << (7 - (x & 0x07));
+            mask = 0x01 << (7 - (x & 0x07));
         }
-        if (AL & 0x80) {
+        if (color & 0x80) {
             data ^= attr;
         } else {
             data &= ~mask;
@@ -550,52 +441,52 @@ biosfn_write_pixel(u8 BH, u8 AL, u16 CX, u16 DX)
         SET_FARVAR(SEG_CTEXT, *addr_far, data);
         break;
     case LINEAR8:
-        addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
-        SET_FARVAR(SEG_GRAPH, *addr_far, AL);
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
         break;
     }
 }
 
-void
-biosfn_read_pixel(u8 BH, u16 CX, u16 DX, u16 *AX)
+u8
+vgafb_read_pixel(u16 x, u16 y)
 {
     // Get the mode
     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
     if (!vmode_g)
-        return;
-    if (GET_GLOBAL(vmode_g->class) == TEXT)
-        return;
+        return 0;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        return 0;
 
     u8 *addr_far, mask, attr=0, data, i;
     switch (GET_GLOBAL(vmode_g->memmodel)) {
     case PLANAR4:
     case PLANAR1:
-        addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
-        mask = 0x80 >> (CX & 0x07);
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
         attr = 0x00;
         for (i = 0; i < 4; i++) {
-            outw((i << 8) | 0x04, VGAREG_GRDC_ADDRESS);
+            vgahw_grdc_write(0x04, i);
             data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
             if (data > 0)
                 attr |= (0x01 << i);
         }
         break;
     case CGA:
-        addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
-        if (DX & 1)
+        addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+        if (y & 1)
             addr_far += 0x2000;
         data = GET_FARVAR(SEG_CTEXT, *addr_far);
         if (GET_GLOBAL(vmode_g->pixbits) == 2)
-            attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
+            attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
         else
-            attr = (data >> (7 - (CX & 0x07))) & 0x01;
+            attr = (data >> (7 - (x & 0x07))) & 0x01;
         break;
     case LINEAR8:
-        addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
         attr = GET_FARVAR(SEG_GRAPH, *addr_far);
         break;
     }
-    *AX = (*AX & 0xff00) | attr;
+    return attr;
 }
 
 
@@ -604,57 +495,15 @@ biosfn_read_pixel(u8 BH, u16 CX, u16 DX, u16 *AX)
  ****************************************************************/
 
 void
-biosfn_load_text_user_pat(u16 ES, u16 BP, u16 CX, u16 DX, u8 BL, u8 BH)
-{
-    get_font_access();
-    u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
-    u16 i;
-    for (i = 0; i < CX; i++) {
-        void *src_far = (void*)(BP + i * BH);
-        void *dest_far = (void*)(blockaddr + (DX + i) * 32);
-        memcpy_far(SEG_GRAPH, dest_far, ES, src_far, BH);
-    }
-    release_font_access();
-}
-
-void
-biosfn_load_text_8_14_pat(u8 BL)
-{
-    get_font_access();
-    u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
-    u16 i;
-    for (i = 0; i < 0x100; i++) {
-        u16 src = i * 14;
-        void *dest_far = (void*)(blockaddr + i * 32);
-        memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont14[src], 14);
-    }
-    release_font_access();
-}
-
-void
-biosfn_load_text_8_8_pat(u8 BL)
-{
-    get_font_access();
-    u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
-    u16 i;
-    for (i = 0; i < 0x100; i++) {
-        u16 src = i * 8;
-        void *dest_far = (void*)(blockaddr + i * 32);
-        memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont8[src], 8);
-    }
-    release_font_access();
-}
-
-void
-biosfn_load_text_8_16_pat(u8 BL)
+vgafb_load_font(u16 seg, void *src_far, u16 count
+                , u16 start, u8 destflags, u8 fontsize)
 {
     get_font_access();
-    u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
+    u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
+    void *dest_far = (void*)(blockaddr + start*32);
     u16 i;
-    for (i = 0; i < 0x100; i++) {
-        u16 src = i * 16;
-        void *dest_far = (void*)(blockaddr + i * 32);
-        memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont16[src], 16);
-    }
+    for (i = 0; i < count; i++)
+        memcpy_far(SEG_GRAPH, dest_far + i*32
+                   , seg, src_far + i*fontsize, fontsize);
     release_font_access();
 }