vgabios: Support custom fonts in vga framebuffer text writing.

Obtain the font data from int 0x43 and int 0x1f, and obtain the font
height from the BDA.  This enables application overrides for the font
data.

This patch also unifies the variable naming between the
planar/CGA/linear character writing functions and uses the same names
that the screen scrolling functions use.

This patch also optimizes the inner loop of the CGA font writing to
reduce overall stack usage.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
index 815d54b..2efaab5 100644
--- a/vgasrc/vgafb.c
+++ b/vgasrc/vgafb.c
@@ -43,7 +43,7 @@
 scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
            , struct cursorpos ul, struct cursorpos lr)
 {
-    int cheight = GET_GLOBAL(vmode_g->cheight);
+    int cheight = GET_BDA(char_height);
     int cwidth = 1;
     int stride = GET_BDA(video_cols) * cwidth;
     void *src_far, *dest_far;
@@ -79,7 +79,7 @@
 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
             , struct cursorpos ul, struct cursorpos lr)
 {
-    int cheight = GET_GLOBAL(vmode_g->cheight) / 2;
+    int cheight = GET_BDA(char_height) / 2;
     int cwidth = GET_GLOBAL(vmode_g->depth);
     int stride = GET_BDA(video_cols) * cwidth;
     void *src_far, *dest_far;
@@ -117,7 +117,7 @@
 scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr
            , struct cursorpos ul, struct cursorpos lr)
 {
-    int cheight = 8;
+    int cheight = GET_BDA(char_height);
     int cwidth = 8;
     int stride = GET_BDA(video_cols) * cwidth;
     void *src_far, *dest_far;
@@ -206,6 +206,21 @@
  * Read/write characters to screen
  ****************************************************************/
 
+static struct segoff_s
+get_font_data(u8 c)
+{
+    int char_height = GET_BDA(char_height);
+    struct segoff_s font;
+    if (char_height == 8 && c >= 128) {
+        font = GET_IVT(0x1f);
+        c -= 128;
+    } else {
+        font = GET_IVT(0x43);
+    }
+    font.offset += c * char_height;
+    return font;
+}
+
 static void
 write_gfx_char_pl4(struct vgamode_s *vmode_g
                    , struct cursorpos cp, struct carattr ca)
@@ -214,28 +229,20 @@
     if (cp.x >= nbcols)
         return;
 
-    u8 cheight = GET_GLOBAL(vmode_g->cheight);
-    u8 *fdata_g;
-    switch (cheight) {
-    case 14:
-        fdata_g = vgafont14;
-        break;
-    case 16:
-        fdata_g = vgafont16;
-        break;
-    default:
-        fdata_g = vgafont8;
-    }
-    u16 addr = cp.x + cp.y * cheight * nbcols;
-    u16 src = ca.car * cheight;
+    struct segoff_s font = get_font_data(ca.car);
+    int cheight = GET_BDA(char_height);
+    int cwidth = 1;
+    int stride = nbcols * cwidth;
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
     int i;
     for (i=0; i<4; i++) {
         stdvga_planar4_plane(i);
         u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00);
         int j;
         for (j = 0; j < cheight; j++) {
-            u8 *dest_far = (void*)(addr + j * nbcols);
-            u8 pixels = colors & GET_GLOBAL(fdata_g[src + j]);
+            u8 *dest_far = (void*)(addr + j * stride);
+            u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+j));
+            u8 pixels = colors & fontline;
             if (ca.attr & 0x80)
                 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
             SET_FARVAR(SEG_GRAPH, *dest_far, pixels);
@@ -252,29 +259,31 @@
     if (cp.x >= nbcols)
         return;
 
-    u8 *fdata_g = vgafont8;
-    u8 bpp = GET_GLOBAL(vmode_g->depth);
-    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);
+    struct segoff_s font = get_font_data(ca.car);
+    int cheight = GET_BDA(char_height) / 2;
+    int cwidth = GET_GLOBAL(vmode_g->depth);
+    int stride = nbcols * cwidth;
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
+    int i;
+    for (i = 0; i < cheight*2; i++) {
+        u8 *dest_far = (void*)(addr + (i >> 1) * stride);
         if (i & 1)
             dest_far += 0x2000;
-        if (bpp == 1) {
+        u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
+        if (cwidth == 1) {
             u8 colors = (ca.attr & 0x01) ? 0xff : 0x00;
-            u8 pixels = colors & GET_GLOBAL(fdata_g[src + i]);
+            u8 pixels = colors & fontline;
             if (ca.attr & 0x80)
                 pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far);
             SET_FARVAR(SEG_CTEXT, *dest_far, pixels);
         } else {
-            u16 pixels = 0;
-            u8 fontline = GET_GLOBAL(fdata_g[src + i]);
-            int j;
-            for (j = 0; j < 8; j++)
-                if (fontline & (1<<j))
-                    pixels |= (ca.attr & 0x03) << (j*2);
-            pixels = cpu_to_be16(pixels);
+            u16 fontline16 = ((fontline & 0xf0) << 4) | (fontline & 0x0f);
+            fontline16 = ((fontline16 & 0x0c0c) << 2) | (fontline16 & 0x0303);
+            fontline16 = ((fontline16 & 0x2222) << 1) | (fontline16 & 0x1111);
+            fontline16 |= fontline16<<1;
+            u16 colors = (((ca.attr & 0x01) ? 0x5555 : 0x0000)
+                          | ((ca.attr & 0x02) ? 0xaaaa : 0x0000));
+            u16 pixels = cpu_to_be16(colors & fontline16);
             if (ca.attr & 0x80)
                 pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far);
             SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels);
@@ -291,14 +300,16 @@
     if (cp.x >= nbcols)
         return;
 
-    u8 *fdata_g = vgafont8;
-    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);
-        u8 fontline = GET_GLOBAL(fdata_g[src + i]);
-        u8 j;
+    struct segoff_s font = get_font_data(ca.car);
+    int cheight = GET_BDA(char_height);
+    int cwidth = 8;
+    int stride = nbcols * cwidth;
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
+    int i;
+    for (i = 0; i < cheight; i++) {
+        u8 *dest_far = (void*)(addr + i * stride);
+        u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
+        int j;
         for (j = 0; j < 8; j++) {
             u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00;
             SET_FARVAR(SEG_GRAPH, dest_far[j], pixel);
@@ -310,16 +321,16 @@
 write_text_char(struct vgamode_s *vmode_g
                 , struct cursorpos cp, struct carattr ca)
 {
-    // Compute the address
-    u16 nbcols = GET_BDA(video_cols);
-    void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
-                                + (cp.x + cp.y * nbcols) * 2);
-
+    int cheight = 1;
+    int cwidth = 2;
+    int stride = GET_BDA(video_cols) * cwidth;
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
+    void *dest_far = (void*)(GET_BDA(video_pagesize) * cp.page + addr);
     if (ca.use_attr) {
         u16 dummy = (ca.attr << 8) | ca.car;
-        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)dest_far, dummy);
     } else {
-        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, ca.car);
     }
 }
 
@@ -366,10 +377,12 @@
     }
 
     // Compute the address
-    u16 nbcols = GET_BDA(video_cols);
-    u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page
-                               + (cp.x + cp.y * nbcols) * 2);
-    u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
+    int cheight = 1;
+    int cwidth = 2;
+    int stride = GET_BDA(video_cols) * cwidth;
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
+    u16 *src_far = (void*)(GET_BDA(video_pagesize) * cp.page + addr);
+    u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *src_far);
     struct carattr ca = {v, v>>8, 0};
     return ca;