Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / vga.c
diff --git a/qemu/roms/openhackware/src/vga.c b/qemu/roms/openhackware/src/vga.c
new file mode 100644 (file)
index 0000000..d671bea
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License V2
+ *   as published by the Free Software Foundation
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+
+/* VGA init. We use the Bochs VESA VBE extensions  */
+#define VBE_DISPI_INDEX_ID              0x0
+#define VBE_DISPI_INDEX_XRES            0x1
+#define VBE_DISPI_INDEX_YRES            0x2
+#define VBE_DISPI_INDEX_BPP             0x3
+#define VBE_DISPI_INDEX_ENABLE          0x4
+#define VBE_DISPI_INDEX_BANK            0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+#define VBE_DISPI_INDEX_X_OFFSET        0x8
+#define VBE_DISPI_INDEX_Y_OFFSET        0x9
+#define VBE_DISPI_INDEX_NB              0xa
+      
+#define VBE_DISPI_ID0                   0xB0C0
+#define VBE_DISPI_ID1                   0xB0C1
+#define VBE_DISPI_ID2                   0xB0C2
+  
+#define VBE_DISPI_DISABLED              0x00
+#define VBE_DISPI_ENABLED               0x01
+#define VBE_DISPI_LFB_ENABLED           0x40
+#define VBE_DISPI_NOCLEARMEM            0x80
+  
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+static void vga_text_init(void);
+
+unsigned long vga_fb_phys_addr;
+int vga_fb_width;
+int vga_fb_height;
+int vga_fb_linesize;
+int vga_fb_bpp;
+int vga_fb_depth;
+uint8_t rgb_to_index[256];
+
+static void vbe_outw(int index, int val)
+{
+    outw(0x1ce, index);
+    outw(0x1d0, val);
+}
+
+/* init VGA in standard state for PREP boot */
+void vga_prep_init(void)
+{
+    outb(0x3c0, 0x00); /* set blanking */
+    vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
+}
+
+/* build standard RGB palette */
+void vga_build_rgb_palette(void)
+{
+    static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
+    int i, r, g, b;
+
+    i = 0;
+    for(r = 0; r < 6; r++) {
+        for(g = 0; g < 6; g++) {
+            for(b = 0; b < 6; b++) {
+                vga_set_palette(i, RGB(pal_value[r], pal_value[g], 
+                                       pal_value[b]));
+                i++;
+            }
+        }
+    }
+    for(i = 0; i < 256; i++) {
+        rgb_to_index[i] = ((i * 5) + 128) / 255;
+    }
+}
+
+void vga_set_address (uint32_t address)
+{
+    vga_fb_phys_addr = address;
+}
+
+/* depth = 8, 15, 16 or 32 */
+void vga_set_mode(int width, int height, int depth)
+{
+    vbe_outw(VBE_DISPI_INDEX_XRES, width);
+    vbe_outw(VBE_DISPI_INDEX_YRES, height);
+    vbe_outw(VBE_DISPI_INDEX_BPP, depth);
+    vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
+    outb(0x3c0, 0x20); /* disable blanking */
+
+    if (vga_fb_phys_addr == 0x00000000)
+        vga_fb_phys_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+    vga_fb_width = width;
+    vga_fb_height = height;
+    vga_fb_depth = depth;
+    vga_fb_bpp = (depth + 7) >> 3;
+    vga_fb_linesize = width * vga_fb_bpp;
+    
+    if (depth == 8)
+        vga_build_rgb_palette();
+    vga_text_init();
+}
+
+/* for depth = 8 mode, set a hardware palette entry */
+void vga_set_palette(int i, unsigned int rgba)
+{
+    unsigned int r, g, b;
+
+    r = (rgba >> 16) & 0xff;
+    g = (rgba >> 8) & 0xff;
+    b = (rgba) & 0xff;
+    outb(0x3c8, i);
+    outb(0x3c9, r >> 2);
+    outb(0x3c9, g >> 2);
+    outb(0x3c9, b >> 2);
+}
+
+/* convert a RGBA color to a color index usable in graphic primitives */
+unsigned int vga_get_color(unsigned int rgba)
+{
+    unsigned int r, g, b, color;
+
+    switch(vga_fb_depth) {
+    case 8:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = (rgb_to_index[r] * 6 * 6) + 
+            (rgb_to_index[g] * 6) + 
+            (rgb_to_index[b]);
+        break;
+    case 15:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+        break;
+    case 16:
+        r = (rgba >> 16) & 0xff;
+        g = (rgba >> 8) & 0xff;
+        b = (rgba) & 0xff;
+        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+        break;
+    case 32:
+    default:
+        color = rgba;
+        break;
+    }
+    return color;
+}
+
+void vga_draw_buf (const void *buf, int buf_linesize,
+                   int posx, int posy, int width, int height)
+{
+    const uint8_t *s;
+    uint8_t *d;
+    int y, wb;
+    
+    s = buf;
+    d = (uint8_t *)vga_fb_phys_addr + 
+        vga_fb_linesize * posy + vga_fb_bpp * posx;
+    wb = width * vga_fb_bpp;
+    for (y = 0; y < height; y++) {
+        memcpy(d, s, wb);
+        s += buf_linesize;
+        d += vga_fb_linesize;
+    }
+}
+
+void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color)
+{
+    uint8_t *d, *d1;
+    int x, y;
+    
+    d1 = (uint8_t *)vga_fb_phys_addr + 
+        vga_fb_linesize * posy + vga_fb_bpp * posx;
+    for (y = 0; y < height; y++) {
+        d = d1;
+        switch(vga_fb_bpp) {
+        case 1:
+            for (x = 0; x < width; x++) {
+                *((uint8_t *)d) = color;
+                d++;
+            }
+            break;
+        case 2:
+            for (x = 0; x < width; x++) {
+                *((uint16_t *)d) = color;
+                d += 2;
+            }
+            break;
+        case 4:
+            for (x = 0; x < width; x++) {
+                *((uint32_t *)d) = color;
+                d += 4;
+            }
+            break;
+        }
+        d1 += vga_fb_linesize;
+    }
+}
+
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h)
+{
+    const uint8_t *s;
+    uint8_t *d;
+    int wb, y;
+
+    wb = w * vga_fb_bpp;
+    if (yd <= ys) {
+        s = (uint8_t *)vga_fb_phys_addr + 
+            vga_fb_linesize * ys + vga_fb_bpp * xs;
+        d = (uint8_t *)vga_fb_phys_addr + 
+            vga_fb_linesize * yd + vga_fb_bpp * xd;
+        for (y = 0; y < h; y++) {
+            memmove(d, s, wb);
+            d += vga_fb_linesize;
+            s += vga_fb_linesize;
+        }
+    } else {
+        s = (uint8_t *)vga_fb_phys_addr + 
+            vga_fb_linesize * (ys + h - 1) + vga_fb_bpp * xs;
+        d = (uint8_t *)vga_fb_phys_addr + 
+            vga_fb_linesize * (yd + h - 1) + vga_fb_bpp * xd;
+       for (y = 0; y < h; y++) {
+            memmove(d, s, wb);
+            d -= vga_fb_linesize;
+            s -= vga_fb_linesize;
+        }
+    }
+}
+
+/***********************************************************/
+/* basic char display */
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+#include "vgafont.h"
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+/* XXX: endianness */
+#if 0
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) x
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+int text_width, text_height, text_fgcol, text_bgcol, text_x, text_y;
+
+static void vga_text_init(void)
+{
+    text_width = vga_fb_width / FONT_WIDTH;
+    text_height = vga_fb_height / FONT_HEIGHT;
+    text_x = 0;
+    text_y = 0;
+    vga_text_set_fgcol(RGB(0xff, 0xff, 0xff));
+    vga_text_set_bgcol(RGB(0x00, 0x00, 0x00));
+}
+
+static inline unsigned int col_expand(unsigned int col)
+{
+    switch(vga_fb_bpp) {
+    case 1:
+        col |= col << 8;
+        col |= col << 16;
+        break;
+    case 2:
+        col |= col << 16;
+        break;
+    default:
+        text_fgcol = 0xffffff;
+        break;
+    }
+
+    return col;
+}
+
+void vga_text_set_fgcol(unsigned int rgba)
+{
+    text_fgcol = col_expand(vga_get_color(rgba));
+}
+
+void vga_text_set_bgcol(unsigned int rgba)
+{
+    text_bgcol = col_expand(vga_get_color(rgba));
+}
+
+void vga_putcharxy(int x, int y, int ch, 
+                   unsigned int fgcol, unsigned int bgcol)
+{
+    uint8_t *d;
+    const uint8_t *font_ptr;
+    unsigned int font_data, linesize, xorcol;
+    int i;
+
+    d = (uint8_t *)vga_fb_phys_addr + 
+        vga_fb_linesize * y * FONT_HEIGHT + vga_fb_bpp * x * FONT_WIDTH;
+    linesize = vga_fb_linesize;
+    font_ptr = vgafont16 + FONT_HEIGHT * ch;
+    xorcol = bgcol ^ fgcol;
+    switch(vga_fb_depth) {
+    case 8:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    case 16:
+    case 15:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    case 32:
+        for(i = 0; i < FONT_HEIGHT; i++) {
+            font_data = *font_ptr++;
+            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+            d += linesize;
+        }
+        break;
+    }
+}
+
+static void vga_put_lf(void)
+{
+    text_x = 0;
+    text_y++;
+    if (text_y >= text_height) {
+        text_y = text_height - 1;
+        vga_bitblt(0, FONT_HEIGHT, 0, 0, 
+                   text_width * FONT_WIDTH, 
+                   (text_height - 1) * FONT_HEIGHT);
+        vga_fill_rect(0, (text_height - 1) * FONT_HEIGHT,
+                      text_width * FONT_WIDTH, FONT_HEIGHT, text_bgcol);
+    }
+}
+
+void vga_putchar(int ch)
+{
+    if (ch == '\r') {
+        text_x = 0;
+    } else if (ch == '\n') {
+        vga_put_lf();
+    } else if (ch == '\b') {
+        if (text_x == 0) {
+            if (text_y != 0) {
+                text_x = text_width;
+                text_y--;
+                goto eat_char;
+            }
+        } else {
+        eat_char:
+            vga_putcharxy(--text_x, text_y, ' ', text_fgcol, text_bgcol);
+        }
+    } else {
+        vga_putcharxy(text_x, text_y, ch, text_fgcol, text_bgcol);
+        text_x++;
+        if (text_x >= text_width)
+            vga_put_lf();
+    }
+}
+
+void vga_puts(const char *s)
+{
+    while (*s) {
+        vga_putchar(*(uint8_t *)s);
+        s++;
+    }
+}