Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

vga.c

/* $Id: vga.c,v 1.67 2009-01-28 16:47:15 potyra Exp $ 
 *
 * Copyright (C) 2004-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include "compiler.h"
CODE16;

#include "assert.h"
#include "stdio.h"

#include "main.h"
#include "const.h"
#include "io.h"
#include "var.h"
#include "ptrace.h"
#include "vesa.h"

#include "vga.h"


extern CONST unsigned char font_8x16[];
extern CONST unsigned char font_8x14[];
extern CONST unsigned char font_8x8[];

#define SCROLL_UP 1
#define SCROLL_DOWN     2

/* #define DEBUG_INT10 */

/*
 * functions
 */
static unsigned short
vga_start(unsigned short rows, unsigned short cols, unsigned short page)
{
      unsigned short size;

      /* Size of each page. */
      size = rows * cols * 2;

      /* Round to next 2K boundary. */
      /* Correct? FIXME VOSSI */
      size = (size + 0x07ff) & 0xf800;

      return size * page;
}

static void
set_cursor_pos(unsigned char page, unsigned char x, unsigned char y)
{
      unsigned short rows;
      unsigned short cols;

      assert(page < 8);

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      /*
       * *Don't* check x/y!
       * It seems to be correct to set cursor outside of screen!
       */
      /* assert(0 <= x && x < cols); */
      /* assert(0 <= y && y < rows); */

      var_put(curspos[page].x, x);
      var_put(curspos[page].y, y);

      /* Set cursor only if page is active page. */
      if (var_get(curr_page) == page) {
            unsigned short start;
            unsigned short offset;

            start = vga_start(rows, cols, page);
            offset = start + (unsigned short) y * cols + (unsigned short) x;

            outb_p(0x0e, 0x3d4);
            outb_p((offset >> 8) & 0xff, 0x3d5);
            outb_p(0x0f, 0x3d4);
            outb_p((offset >> 0) & 0xff, 0x3d5);
      }
}

static void
write_text_char(
      unsigned char page,
      unsigned char x,
      unsigned char y,
      unsigned char car,
      unsigned char attr,
      int attrflag
)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short start;
      unsigned short offset;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      start = vga_start(rows, cols, page);
      offset = start + ((unsigned short) y * cols + (unsigned short) x) * 2;

      put_byte(0xb800, (unsigned char *) (offset + 0), car);
      if (attrflag) {
            put_byte(0xb800, (unsigned char *) (offset + 1), attr);
      }
}

static void
write_gfx_char(
      unsigned char page,
      unsigned char x,
      unsigned char y,
      unsigned char car,
      unsigned char attr,
      int attrflag            /* Not used for graphics mode. */
)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short i;
      unsigned char bits;
      unsigned long offset;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      outw((0x0f << 8) | 2, 0x03c4);      /* seq_map_mask = 0xf */
      outw((0x0f << 8) | 1, 0x03ce);      /* gr_enable_set_reset = 0xf */
      outw((0x00 << 8) | 5, 0x03ce);      /* gr_mode = 0 */

      /* First we set (or XOR) the foreground pixels. */
      outw(((attr & 0x0f) << 8) | 0, 0x03ce); /* gr_set_reset = fgcolor */
      if ((attr >> 7) & 1) {
            /* attr is the color. If bit 7 is set, the current content
             * of the screen gets XOR'd with the character. */
            outw((((3 << 3) | 0) << 8) | 3, 0x03ce); /*xor mode, no rotate*/
      } else {
            outw((((0 << 3) | 0) << 8) | 3, 0x03ce); /*nop mode, no rotate*/
      }

      for (i = 0; i < 16; i++) {
            offset = (y * cols * 16) + (i * cols) + x; 
            /* Dummy Read to Load the VGAs internal latches */
            (void) get_byte(0xa000, (unsigned char *) offset);
            bits = const_get(font_8x16[car * 16 + i]);
            outw((bits << 8) | 8, 0x03ce);      /* gr_bit_mask = font */
            put_byte(0xa000, (unsigned char *) offset, 0);
      }

      if (! ((attr >> 7) & 1)) {
            /* Now we set the background pixels too, but only if we're
             * not XORing of course. */
            /* gr_set_reset = bgcolor */
            outw((((attr >> 4) & 0x07) << 8) | 0, 0x03ce);
            /* we don't need to set "nop mode, no rotate" again */

            for (i = 0; i < 16; i++) {
                  offset = (y * cols * 16) + (i * cols) + x; 
                  /* Dummy Read to Load the VGAs internal latches */
                  (void) get_byte(0xa000, (unsigned char *) offset);
                  bits = ~const_get(font_8x16[car * 16 + i]);
                  outw((bits << 8) | 8, 0x03ce); /* gr_bit_mask = ~font */
                  put_byte(0xa000, (unsigned char *) offset, 0);
            }
      }
}

static void
write_char(
      unsigned char page,
      unsigned char x,
      unsigned char y,
      unsigned char car,
      unsigned char attr,
      int attrflag
) {
#if 0
      assert(/* 0 <= x && */ x < var_get(vid_columns));
      assert(/* 0 <= y && */ y < var_get(vid_rows) + 1);
#endif

      if (var_get(vid_mode) == 0x03 || var_get(vid_mode) == 0x02) {
            write_text_char(page, x, y, car, attr, attrflag);

      } else if (var_get(vid_mode) == 0x12) {
            write_gfx_char(page, x, y, car, attr, attrflag);
      }
}

static void
scroll_text(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char direction,
      unsigned char numlines
)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short x;
      unsigned short y;
      unsigned long diff;
      unsigned long start;
      unsigned long offset;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

#if 0
      assert(left < cols);
      assert(top < rows);
      assert(right < cols);
      assert(bottom < rows);
      assert(left <= right);
      assert(top <= bottom);
#endif

      start = vga_start(rows, cols, page);
      diff = cols * numlines * 2;

      if (direction == SCROLL_UP) {
            for (y = top; y <= bottom - numlines; y++) {
                  offset = start + y * cols * 2;
                  for (x = left; x <= right; x++) {
                        put_word(0xb800, (unsigned short *) offset, 
                              get_word(0xb800, (unsigned short *) (offset + diff)));
                        offset += 2;
                  }
            }
      } else {
            for (y = bottom; top + numlines <= y; y--) {
                  offset = start + y * cols * 2;
                  for (x = left; x <= right; x++) {
                        put_word(0xb800, (unsigned short *) offset, 
                              get_word(0xb800, (unsigned short *) (offset - diff)));
                        offset += 2;
                  }
            }
      }
}

static void
scroll_graphics_4bit(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char direction,
      unsigned char numlines
)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short x;
      unsigned short y;
      unsigned long diff;
      unsigned short start;
      unsigned long offset;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      diff = cols * numlines * 16;
      start = vga_start(rows, cols, page);

            outw(0x0105, 0x3ce);    /* UMVGA->mode:         read: 0 write: 1 */
      outw(0xff08, 0x3ce);    /* UMVGA->bit_mask:     0xff */
      outw(0x0f02, 0x3c4);    /* UMVGA->map_mask:     planes 0-3 */

      if (direction == SCROLL_UP) {
            for (y = top * 16; y < (bottom - numlines + 1) * 16; y++) {
                  offset = start + y * cols;
                  for (x = left; x <= right; x++) {
                        /* scroll up */
                        /* load latches */
                        get_byte(0xa000, (unsigned char *) (offset + diff));
                        /* write latches - just dummy value */
                        put_byte(0xa000, (unsigned char *) offset, 0x00);
                        offset++;
                  }
            }
      } else {
            for (y = bottom * 16; (top + numlines + 1) * 16 < y; y--) {
                  offset = start + y * cols;
                  for (x = left; x <= right; x++) {
                        /* scroll up */
                        /* load latches */
                        get_byte(0xa000, (unsigned char *) (offset - diff));
                        /* write latches - just dummy value */
                        put_byte(0xa000, (unsigned char *) offset, 0x00);
                        offset++;
                  }
            }
      }
}

static void
scroll(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char direction,
      unsigned char numlines
) {
      if (var_get(vid_mode) == 0x03 || var_get(vid_mode) == 0x02) {
            /* text mode - 80 x 25 */
            scroll_text(page, left, top, right, bottom,
                  direction, numlines);
      } else if (var_get(vid_mode) == 0x12) {
            /* graphics mode - 4 bit plane mode - 640 x 480 */
            scroll_graphics_4bit(page, left, top, right, bottom,
                  direction, numlines);
      }
}

static void
clear_text(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char attr
) {
      unsigned short rows;
      unsigned short cols;
      unsigned char x;
      unsigned char y;
      unsigned short start;
      unsigned short offset;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

#if 0
      assert(left < cols);
      assert(top < rows);
      assert(right < cols);
      assert(bottom < rows);
      assert(left <= right);
      assert(top <= bottom);
#endif

      start = vga_start(rows, cols, page);

      for (y = top; y <= bottom; y++) {
            offset = start + (y * cols + left) * 2;
            for (x = left; x <= right; x++) {
                  put_byte(0xb800, (unsigned char *) (offset + 0), ' ');
                  put_byte(0xb800, (unsigned char *) (offset + 1), attr);
                  offset += 2;
            }
      }
}

static void
clear_graphics_4bit(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char attr
)
{
      unsigned short cols;
      unsigned short x;
      unsigned short y;
      unsigned long offset;

      cols = var_get(vid_columns);

            outw( 0x0005, 0x3ce);         /* UMVGA->mode: read 0 write 0 */
      outw( 0x0f02, 0x3c4);         /* UMVGA->map_mask: planes 0-3 */
      outw( (attr % 16) << 8, 0x3ce);     /* UMVGA->set_reset: write to color planes */
      outw( 0x0f01, 0x3ce);         /* UMVGA->enable_set_reset: planes 0-3 */
      outw( 0xff08, 0x3ce);         /* UMVGA->bit_mask: all bits */
      for (y = top * 16; y < (bottom + 1) * 16; y++) {
            offset = y * cols + left;
            for (x = left; x <= right; x++) {
                  put_byte(0xa000, (unsigned char *) offset, attr);
                  offset++;
            }
      }
}

static void
clear(
      unsigned short page,
      unsigned char left,
      unsigned char top,
      unsigned char right,
      unsigned char bottom,
      unsigned char attr
) {
      if (var_get(vid_mode) == 0x03 || var_get(vid_mode) == 0x02) {
            /* text mode - 80 x 25 */
            clear_text(page, left, top, right, bottom, attr);

      } else if (var_get(vid_mode) == 0x12) {
            /* graphics mode - 4 bit plane mode - 640 x 480 */
            clear_graphics_4bit(page, left, top, right, bottom, attr);
      }
}

void
write_teletype(
      unsigned char c,
      unsigned char page,
      unsigned char attr,
      int aflag
) {
      unsigned short rows;
      unsigned short cols;
      unsigned char x;
      unsigned char y;

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      if (page == 0xff) {
            /* Write to active page. */
            page = var_get(curr_page);
      }

      x = var_get(curspos[page].x);
      y = var_get(curspos[page].y);

      assert(/* 0 <= x && */ x < cols);
      assert(/* 0 <= y && */ y < rows);


      if (c == 7) {
            /* beep - FIXME MARCEL */

      } else if (c == 8) {
            /* back space */
            if (0 < x) {
                  x --;
            }

      } else if (c == '\t') {
            /* tabulator */
            do {
                  write_char(page, x, y, ' ', attr, aflag);
                  x++;
            } while (x % 8 != 0);

      } else if (c == '\n') {
            /* newline */
            x = 0;
            y++;

      } else if (c == '\r') {
            /* carridge return */
            x = 0;

      } else {
            write_char(page, x, y, c, attr, aflag);

            x++;
            if (x == cols) {
                  x = 0;
                  y++;
            }
      }
      if (y == rows) {
            scroll(page, 0, 0, cols - 1, rows - 1, SCROLL_UP, 1);
            clear(page, 0, rows - 1, cols - 1, rows - 1, 0x7);
            y--;
      }

      set_cursor_pos(page, x, y);
}

static void
biosfn_load_text_user_pat(
      unsigned short es,
      unsigned short bp,
      unsigned short cx,
      unsigned short dx,
      unsigned char bl,
      unsigned char bh)
{
      unsigned short blockaddr;
      unsigned short i;
      unsigned short dest;
      unsigned short src;
      unsigned short c;

      /*
       * Get font access.
       */
      /* See linux/drivers/video/vgacon.c. */
      outb_p(0x00, 0x03c4); /* Synchronous reset */
      outb_p(0x01, 0x03c5);
      outb_p(0x02, 0x03c4); /* CPU writes only to map 2 */
      outb_p(0x04, 0x03c5);
      outb_p(0x04, 0x03c4); /* Sequential addressing */
      outb_p(0x07, 0x03c5);
      outb_p(0x00, 0x03c4); /* Clear synchronous reset */
      outb_p(0x03, 0x03c5);

      outb_p(0x04, 0x03ce); /* Select map 2 */
      outb_p(0x02, 0x03cf);
      outb_p(0x05, 0x03ce); /* disable odd-even addressing */
      outb_p(0x00, 0x03cf);
      outb_p(0x06, 0x03ce); /* map start at A000:0000 */
      outb_p(0x00, 0x03cf);

      /*
       * Re-write font data.
       */
      blockaddr = ((bl & 0x03) << 14) + ((bl & 0x04) << 11);
      for (i = 0; i < cx; i++) {
            src = bp + i * bh;
            dest = blockaddr + (dx + i) * 32;
            for (c = 0; c < bh; c++) {
                  put_byte(0xa000, dest + c, get_byte(es, src + c));
            }
            for ( ; c < 32; c++) {
                  put_byte(0xa000, dest + c, 0);
            }
      }

      /*
       * Release font access.
       */
      /* See linux/drivers/video/vgacon.c. */
      outb_p(0x00, 0x03c4); /* Synchronous reset */
      outb_p(0x01, 0x03c5);
      outb_p(0x02, 0x03c4); /* CPU writes to maps 0 and 1 */
      outb_p(0x03, 0x03c5);
      outb_p(0x04, 0x03c4); /* odd-even addressing */
      outb_p(0x03, 0x03c5);
      outb_p(0x00, 0x03c4); /* Clear synchronous reset */
      outb_p(0x03, 0x03c5);

      outb_p(0x04, 0x03ce); /* Select map 0 for CPU */
      outb_p(0x00, 0x03cf);
      outb_p(0x05, 0x03ce); /* enable odd-even addressing */
      outb_p(0x10, 0x03cf);
      outb_p(0x06, 0x03ce); /* map start at B000:0000/B800:0000 */
      if (1 /* inb_p(0x3cc) & 1 */) {     /* FIXME VOSSI */
            outb_p(0x0e, 0x03cf);
      } else {
            outb_p(0x0a, 0x03cf);
      }
}

static void
biosfn_load_text_8_14_pat(unsigned char bl)
{
      biosfn_load_text_user_pat(PTR_SEG(font_8x14), PTR_OFF(font_8x14),
                  256, 0, bl, 14);
}

static void
biosfn_load_text_8_8_pat(unsigned char bl)
{
      biosfn_load_text_user_pat(PTR_SEG(font_8x8), PTR_OFF(font_8x8),
                  256, 0, bl, 8);
}

static void
biosfn_load_text_8_16_pat(unsigned char bl)
{
      biosfn_load_text_user_pat(PTR_SEG(font_8x16), PTR_OFF(font_8x16),
                  256, 0, bl, 16);
}

static void
set_scan_lines(unsigned int lines)
{
      unsigned short crtc_addr;
      unsigned char msl;
      unsigned short vde;
      unsigned char ovl;
      unsigned short rows;
      unsigned short cols;

      crtc_addr = var_get(vid_io);

      /*
       * Set maximum scan line register.
       */
      outb(0x09, crtc_addr);
      msl = inb(crtc_addr + 1);
      msl &= 0xe0;
      msl |= lines - 1;
      outb(msl, crtc_addr + 1);

      /*
       * Set cursor shape.
       */
      if (lines == 8) {
            set_cursor_shape(0x06, 0x07);
      } else {
            set_cursor_shape(lines - 4, lines - 3);
      }

      /*
       * Set character height variable.
       */
      var_put(vid_cheight, lines);

      /*
       * Read vertical display end register.
       */
      outb(0x12, crtc_addr);
      vde = inb(crtc_addr + 1);     /* Bit 0-7 */
      outb(0x07, crtc_addr);
      ovl = inb(crtc_addr + 1);
      vde += ((ovl >> 1) & 1) << 8; /* Bit 8 */
      vde += ((ovl >> 6) & 1) << 9; /* Bit 9 */
      vde += 1;

      /*
       * Set number of rows variable.
       */
      rows = vde / lines;
      var_put(vid_rows, rows - 1);

      /*
       * Set page size variable.
       */
      cols = var_get(vid_columns);
      var_put(vid_pagesize, rows * cols * 2);
}

/****************************************
 *                            *
 * Base VGA BIOS functions          *
 *                            *
 ****************************************/

/*
 * VGA Function 00: Set VGA mode
 *
 * In:      AH    = 00h
 *    AL    = mode
 *
 * Out:     -
 */
void
bios_10_00xx(struct regs *regs)
{
      unsigned short i;

#ifdef DEBUG_INT10
        dprintf("VGA Function 00: Set VGA mode: AX=0x04x\n", AX);
#endif

      if (0x13 < (AL & 0x7f)) {
            cirrus_set_mode(AL);
            return;
      }

      set_mode(AL);

      /* set cursor shape */
      set_cursor_shape(14, 15);

      /* active page = 0 */
      var_put(curr_page, 0);

      /* reset cursor positions */
      for (i = 0; i < 8; i++) {
            set_cursor_pos(i, 0, 0);
      }
}

/*
 * VGA Function 01: set text mode cursor shape
 *
 * In:      AH    = 01h
 *    CH    = cursor start and options
 *            (bit 7:   0)
 *            (bits 5-6:      cursor blink, 00=normal, other=invisible)
 *            (bits 4-0:      topmost scan line containing cursor)
 *    CL    = bottom scan line containing cursor (bits 0-4)
 *
 * Out:     -
 */
void
bios_10_01xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 01: set text mode cursor shape.\n");
#endif
      set_cursor_shape(CH, CL);
}

/*
 * VGA Function 02: Write cursor position
 *
 * In:      AH    = 02h
 *    BH    = page #
 *    DH    = row
 *    DL    = column
 *
 * Out:     -
 */
void
bios_10_02xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 02: Write cursor position.\n");
#endif
      set_cursor_pos(BH, DL, DH);
}

/*
 * VGA Function 03: Read cursor position
 *
 * In:      AH    = 03h
 *    BH    = page number
 *
 * Out:     DH    = current cursor row
 *    DL    = current cursot column
 *    CH    = cursor start line
 *    CL    = cursor stop line
 */
void
bios_10_03xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 03: Read cursor position.\n");
#endif
      if (8 <= BH) {
            /* Default. */
            DL = 0;
            DH = 0;
            CH = 0;
            CL = 0;
      } else {
            DL = var_get(curspos[BH].x);
            DH = var_get(curspos[BH].y);
            CH = var_get(curs_start);
            CL = var_get(curs_end);
      }
}

/*
 * VGA Function 04: Read light pen/cursor address
 *
 * In:      AH    = 04h
 *    BH    = page number
 *
 * Out:     AH    = 0x00 light pen switch not down
 *          = 0x01 results returned in DH,DL,CH,BX
 *    DH    = row of light pen
 *    DL    = column of light pen
 *    CH    = raster line (0..199)
 *    BX    = pixel column (0..319/639)
 */
void
bios_10_04xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 04: Read light pen/cursor address.\n");
#endif
      AH = 0;
}

/*
 * VGA Function 05: Set active display page
 *
 * In:      AH    = 05h
 *    AL    = page number
 *
 * Out:     -
 */
void
bios_10_05xx(struct regs *regs)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short start;
      unsigned short ioport;

      if (8 <= AL) {
            return;
      }

#ifdef DEBUG_INT10
        dprintf("VGA Function 05: Set active display page: AL=0x%02x\n", AL);
#endif

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);
      
      var_put(curr_page, AL);

      start = vga_start(rows, cols, AL);
      var_put(vid_pageoff, start);

      ioport = var_get(vid_io);

      /* display buffer: set start address */
      outb_p(0x0c, ioport);
      outb_p(start >> 8, ioport + 1);
      outb_p(0x0d, ioport);
      outb_p(start & 0xff, ioport + 1);

      set_cursor_pos(AL, var_get(curspos[AL].x), var_get(curspos[AL].y));
}

/*
 * VGA Function 06: Scroll window up (active page)
 *
 * In:      AH    = 06h
 *    AL    = number of lines to scroll (0: clear window)
 *    BH    = attribute to use to clear lines at bottom of window
 *    CH    = upper left corner (row)
 *    CL    = upper left corner (column)
 *    DH    = lower right corner (row)
 *    DL    = lower right corner (column)
 *
 * Out:     -
 */
void
bios_10_06xx(struct regs *regs)
{
      unsigned short page;

#ifdef DEBUG_INT10
        dprintf("VGA Function 06: Scroll window up.\n");
#endif

      page = var_get(curr_page);

      if (AL == 0) {
            /* Clear screen. */
            clear(page, CL, CH, DL, DH, BH);

      } else {
            /* Scroll lines. */
            scroll(page, CL, CH, DL, DH, SCROLL_UP, AL);
            /* Clear rest */
            clear(page, CL, DH - AL + 1, DL, DH, BH);
      }
}

/*
 * VGA Function 07: Scroll window down (active page)
 *
 * In:      AH    = 07h
 *    AL    = number of lines to scroll (0: clear window)
 *    BH    = attribute to use to clear lines at bottom of window
 *    CH    = upper left corner (row)
 *    CL    = upper left corner (column)
 *    DH    = lower right corner (row)
 *    DL    = lower right corner (column)
 *
 * Out:     -
 */
void
bios_10_07xx(struct regs *regs)
{
      unsigned short page;

#ifdef DEBUG_INT10
        dprintf("VGA Function 07: Scroll window down.\n");
#endif

      page = var_get(curr_page);

      if (AL == 0) {
            /* Clear screen. */
            clear(page, CL, CH, DL, DH, BH);

      } else {
            /* Scroll lines. */
            scroll(page, CL, CH, DL, DH, SCROLL_DOWN, AL);
            /* Clear rest */
            clear(page, CL, CH, DL, CH + AL, BH);
      }
}

/*
 * VGA Function 08: read character and attribute at cursor position
 *
 * In:      AH    = 08h
 *    BH    = page #
 *
 * Out:     AH    = character attribute
 *    AL    = character
 */
void
bios_10_08xx(struct regs *regs)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short start;
      unsigned short offset;
      unsigned short x;
      unsigned short y;

#ifdef DEBUG_INT10
        dprintf("VGA Function 08: read character and attribute.\n");
#endif

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      x = var_get(curspos[BH].x);
      y = var_get(curspos[BH].y);

      start = vga_start(rows, cols, BH);
      offset = start + (y * cols + x) * 2;

      AL = get_byte(0xb800, (unsigned char *) (offset + 0));
      AH = get_byte(0xb800, (unsigned char *) (offset + 1));
}

/*
 * VGA Function 09: Print characters with attribute
 *
 * In:      AH    = 09h
 *    AL    = ACSII code
 *    BL    = color/attribute
 *    BH    = page #
 *    CX    = # of repetitions
 *
 * Out:     -
 */
void
bios_10_09xx(struct regs *regs)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short x;
      unsigned short y;
      unsigned short i;

#ifdef DEBUG_INT10
        dprintf("VGA Function 09: Print characters with attribute.\n");
#endif

      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      x = var_get(curspos[BH].x);
      y = var_get(curspos[BH].y);

      assert(/* 0 <= x && */ x < cols);
      assert(/* 0 <= y && */ y < rows);

      for (i = 0; i < CX; i++) {
            write_char(BH, x, y, AL, BL, 1);
            x++;
            if (x == 80) {
                  x = 0;
                  y++;
            }
      }
}

/*
 * VGA Function 0a: Print character only at cursor position
 *
 * In:      AH    = 0ah
 *    AL    = character to display
 *    BL    = attribute
 *    BH    = page #
 *    CX    = number of times to write character
 *
 * Out:     -
 */
void
bios_10_0axx(struct regs *regs)
{
      unsigned short rows;
      unsigned short cols;
      unsigned short x;
      unsigned short y;
      unsigned short i;

#ifdef DEBUG_INT10
        dprintf("VGA Function 0a: Print character only at cursor.\n");
#endif
      rows = var_get(vid_rows) + 1;
      cols = var_get(vid_columns);

      x = var_get(curspos[BH].x);
      y = var_get(curspos[BH].y);

      assert(/* 0 <= x && */ x < cols);
      assert(/* 0 <= y && */ y < rows);

      for (i = 0; i < CX; i++) {
            if (cols <= x + i) {
                  break;
            }
            write_char(BH, x + i, y, AL, BL, 0);
      }
}

/*
 * VGA Function 0b: Set background color or palette.
 *
 * In:      AH    = 0bh
 *    BH    = 0:  set background color
 *            1:  set border color
 *
 *    BL    = color
 * Out:     -
 */
void
bios_10_0bxx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 0b: Set background color or palette.\n");
#endif

      if (BH != 0x00 && BH != 0x01) {
            assert(0);  /* FIXME VOSSI */

      } else {
            unsigned char al;
            unsigned char cl;

            (void) inb(0x3da);

            if (BH == 0x00) {
                  outb(0x00, 0x3c0);
                  al = BL & 0x0f;
                  if (al & 0x08) {
                        al += 0x08;
                  }
                  outb(al, 0x3c0);
            }

            for (cl = 0x01; cl != 0x04; cl++) {
                  outb(cl, 0x3c0);
                  al = inb(0x3c1);
                  al &= 0xef;
                  al |= BL & 0x10;
                  outb(al, 0x3c0);
            }

            outb(0x20, 0x3c0);
      }
}

/*
 * VGA Function 0c: Write pixel
 *
 * In:      AH    = 0ch
 *    AL    = pixel color
 *            (if bit 7 is set use XOR mode)
 *    BH    = page #
 *    CX    = column
 *    DX    = row
 */
void
bios_10_0cxx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 0c: Write pixel\n");
#endif
      if (var_get(vid_mode) == 0x12) {
            unsigned short addr;
            unsigned char mask;

            addr = CX / 8 + DX * var_get(vid_columns);
            mask = 0x80 >> (CX & 0x07);

            outw((mask << 8) | 0x08, 0x03ce);
            outw(0x0205, 0x03ce);
            if (AL & 0x80) {
                  outw(0x1803, 0x03ce);
            }

            (void) get_byte(0xa000, addr);
            put_byte(0xa000, addr, AL);

            outw(0xff08, 0x03ce);
            outw(0x0005, 0x03ce);
            outw(0x0003, 0x03ce);
      }
}

/*
 * VGA Function 0e: Print character in TTY mode
 *
 * In:      AH    = 0eh
 *    AL    = ASCII code
 *    BL    = foreground color
 *    BH    = page #
 *
 * Out:     -
 */
void
bios_10_0exx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 0e: Print character.\n");
#endif

      /* interpret char */
      write_teletype(AL, 0xff, BL, 0);
}

/*
 * VGA Function 0f: Read video status
 *
 * In:      AH    = 0fh
 *
 * Out:     AL    = video mode
 *    AH    = # of chars per line
 *    BH    = current page #
 */
void
bios_10_0fxx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 0f: Read video status\n");
#endif
      AH = var_get(vid_columns);
      AL = var_get(vid_mode) | (var_get(video_ctl) & 0x80);
      BH = var_get(curr_page);
}

/*
 * VGA Function 1000: set single palette register
 *
 * In:      AX    = 1000h
 *    BL    = palette register number
 *            (higher values address other attribute controller regs)
 *    BH    = color register number
 *
 * Out:     -
 */
void
bios_10_1000(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1000: set single palette register\n");
#endif
      (void) inb(0x03da);     /* Clear reg/value flag. */
      outb(BL, 0x03c0); /* Write register number. */
      outb(BH, 0x03c0); /* Write new value. */
}

/*
 * VGA Function 1002: set all palette registers
 *
 * In:      AX    = 1002h
 *    ES:DX = palette register list
 *            16+1 byte entries (0x10 = border color)
 *    BH    = 00h to avoid problems on some adapters
 *
 * Out:     -
 */
void
bios_10_1002(struct regs *regs)
{
      unsigned short i;
      unsigned char col;

#ifdef DEBUG_INT10
        dprintf("VGA Function 1002: set all palette registers.\n");
#endif
      for (i = 0; i < 0x10; i++) {
            col = get_byte(ES, (unsigned char *) (DX + i));
            (void) inb(0x03da);     /* Clear reg/value flag. */
            outb(i, 0x03c0);  /* Write register number. */
            outb(col, 0x03c0);      /* Write new value. */
      }

      col = get_byte(ES, (unsigned char *) (DX + 0x10));
      (void) inb(0x03da);     /* Clear reg/value flag. */
      outb(0x11, 0x03c0);     /* Write register number. */
      outb(col, 0x03c0);      /* Write new value. */

      (void) inb(0x03da);     /* Clear reg/value flag. */
      outb(0x20, 0x03c0);     /* Write register number. */
}

/*
 * VGA Function 1003: Set/reset intensity/blinking attribute.
 *
 * In:      AH    = 10h
 *    AL    = 03h
 *    BL    = 0: enable intensity
 *            1: enable blinking
 * Out:     -
 */
void
bios_10_1003(struct regs *regs)
{
      unsigned char state;
      unsigned char value;

#ifdef DEBUG_INT10
        dprintf("VGA Function 1003: Set/reset intensity/blinking.\n");
#endif
      state = BL & 0x01;

      (void) inb(0x03da);

      outb(0x10, 0x03c0);
      value = inb(0x03c1);
      value &= 0xf7;
      value |= state << 3;
      outb(value, 0x03c0);
      outb(0x20, 0x03c0);
}

/*
 * VGA Function 1007: get individual palette register
 *
 * In:      AX    = 1007h
 *    BL    = palette or attribute register number
 *
 * Out:     BH    = palette or attribute register value
 */
void
bios_10_1007(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1007: get individual palette register.\n");
#endif
      (void) inb(0x03da);

      outb(BL, 0x03c0);
      BH = inb(0x03c1);

      (void) inb(0x03da);

      outb(0x20, 0x03c0);
}

/*
 * VGA Function 1009: read all palette registers
 *
 * In:      AX    = 1009h
 *    ES:DX = buffer for palette register values
 *
 * Out:     -
 */
void
bios_10_1009(struct regs *regs)
{
      unsigned short i;
      unsigned char col;

#ifdef DEBUG_INT10
        dprintf("VGA Function 1009: read all palette registers.\n");
#endif
      for (i = 0; i < 0x10; i++) {
            (void) inb(0x03da);     /* Clear reg/value flag. */
            outb(i, 0x03c0);  /* Write register number. */
            col = inb(0x03c0);      /* Read color value. */
            put_byte(ES, (unsigned char *) (DX + i), col);
      }

      (void) inb(0x03da);     /* Clear reg/value flag. */
      outb(0x11, 0x03c0);     /* Write register number. */
      col = inb(0x03c0);      /* Read color value. */
      put_byte(ES, (unsigned char *) (DX + i), col);

      (void) inb(0x03da);     /* Clear reg/value flag. */
      outb(0x20, 0x03c0);     /* Write register number. */
}

/*
 * VGA Function 1010: set individual DAC register
 *
 * In:      AX    = 1010h
 *    BX    = color register
 *    CH    = green value (0-63)
 *    CL    = blue value (0-63)
 *    DH    = red value (0-63)
 *
 * Out:     -
 */
void
bios_10_1010(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1010: set individual DAC.\n");
#endif
      outb(BL, 0x03c8); /* choose DAC entry */
      outb(DH, 0x03c9); /* red */
      outb(CH, 0x03c9); /* green */
      outb(CL, 0x03c9); /* blue */
}

/*
 * VGA Function 1012: set block of DAC registers
 *
 * In:      AX    = 1012h
 *    BX    = starting color register
 *    CX    = # of registers to set
 *    ES:DX = ptr to palette values (RGB: 0..63)
 *
 * Out:     -
 */
void
bios_10_1012(struct regs *regs)
{
      unsigned short i;

#ifdef DEBUG_INT10
        dprintf("VGA Function 1012: set block of DAC.\n");
#endif
      outb(0xff, 0x03c6);     /* set DAC mask register - access to all colors */
      outb(BL, 0x03c8); /* set DAC - start color */
      for (i = 0; i < CX * 3; i++) {
            outb(get_byte(ES, (unsigned char *) (DX + i)), 0x03c9);
      }
}

/*
 * VGA Function 1015: read DAC register
 *
 * In:      AX    = 1015h
 *    BL    = register #
 *
 * Out:     DH    = red
 *    CH    = green
 *    CL    = blue
 */
void
bios_10_1015(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1015: read DAC register.\n");
#endif
      outb(BL, 0x03c7); /* choose DAC entry */
      DH = inb(0x03c9);
      CH = inb(0x03c9);
      CL = inb(0x03c9);
}

/*
 * VGA Function 11: different sub-functions
 *
 * In:      AH    = 11h
 *    AL    = subfunction #
 *
 * subfunction 0x30:
 * Out:     CX    = bytes per character
 *    DL    = # of columns
 *    ES:BP = pointer to font table
 */
void
bios_10_11xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 11: different sub-functions: AL=0x%02x\n", AL);
#endif
      if (AL == 0x00
       || AL == 0x10) {
            /*
             * Load user defined font.
             */
            biosfn_load_text_user_pat(ES, BP, CX, DX, BL, BH);
            if (AL == 0x10) {
                  set_scan_lines(BH);
            }

      } else if (AL == 0x01
            || AL == 0x11) {
            /*
             * Load 8x14 font.
             */
            biosfn_load_text_8_14_pat(BL);
            if (AL == 0x11) {
                  set_scan_lines(14);
            }

      } else if (AL == 0x03) {
            /*
             * Set block specifier.
             */
            outb(3, 0x03c4);  /* Address character_map_select. */
            outb(BL, 0x03c5);

      } else if (AL == 0x02
            || AL == 0x12) {
            /*
             * Load 8x8 font.
             */
            biosfn_load_text_8_8_pat(BL);
            if (AL == 0x12) {
                  set_scan_lines(8);
            }

      } else if (AL == 0x04
            || AL == 0x14) {
            /*
             * Load 8x16 font.
             */
            biosfn_load_text_8_16_pat(BL);
            if (AL == 0x14) {
                  set_scan_lines(16);
            }

      } else if (AL == 0x30) {
            /*
             * Get font info.
             */
            if (BH == 0x00) {
                  /* INT 1Fh pointer */
                  ES = get_word(0x0000, (unsigned short *) (0x1f*4 + 0));
                  BP = get_word(0x0000, (unsigned short *) (0x1f*4 + 2));

            } else if (BH == 0x01) {
                  /* INT 43h pointer */
                  ES = get_word(0x0000, (unsigned short *) (0x43*4 + 0));
                  BP = get_word(0x0000, (unsigned short *) (0x43*4 + 2));

            } else if (BH == 0x02) {
                  ES = PTR_SEG(font_8x14);
                  BP = PTR_OFF(font_8x14);

            } else if (BH == 0x03) {
                  ES = PTR_SEG(font_8x8);
                  BP = PTR_OFF(font_8x8);

            } else if (BH == 0x04) {
                  ES = PTR_SEG(&font_8x8[128 * 8]);
                  BP = PTR_OFF(&font_8x8[128 * 8]);

            } else if (BH == 0x05) {
#if 0 /* FIXME VOSSI */
                  ES = PTR_SEG(font_8x14_alt);
                  BP = PTR_OFF(font_8x14_alt);
#else
                  ES = PTR_SEG(font_8x14);
                  BP = PTR_OFF(font_8x14);
#endif

            } else if (BH == 0x06) {
                  ES = PTR_SEG(font_8x16);
                  BP = PTR_OFF(font_8x16);

            } else if (BH == 0x07) {
#if 0 /* FIXME VOSSI */
                  ES = PTR_SEG(font_8x16_alt);
                  BP = PTR_OFF(font_8x16_alt);
#else
                  ES = PTR_SEG(font_8x16);
                  BP = PTR_OFF(font_8x16);
#endif

            } else {
                  /* FIXME VOSSI */
            }
            CX = var_get(vid_cheight);
            DL = var_get(vid_rows);
      }
}

/*
 * VGA Function 12: different sub-functions
 *
 * In:      AH    = 12h
 *    BL    = sub-function #
 */
void
bios_10_12xx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 12: different sub-functions: BL=0x%02x\n", BL);
#endif
      if (BL == 0x10) {
            /*
             * Get EGA info.
             */
            /* Feature connector bits. */
            CH = 0x00;

            /* Switch settings. */
            CL = var_get(switches) & 0x0f;

            /* Color/monochrome mode. */
            if (var_get(vid_io) == 0x03d4) {
                  BH = 0x00;  /* Color */
            } else {
                  BH = 0x01;  /* Monochrome */
            }

            /* Installed memory (256kB). */
            BL = 0x03;

      } else if (BL == 0x20) {
            /* biosfn_alternate_prtsc() */
            /* Not implemented yet - FIXME VOSSI */

      } else if (BL == 0x30) {
            AX = 0x1212;      /* function supported */
                        /* FIXME VOSSI */

      } else if (BL == 0x31) {
            AH = 0x31;
            for (;;);   /* FIXME VOSSI */
            AL = 0x12;  /* function supported */

      } else if (BL == 0x32) {
            AH = 0x32;
            for (;;);   /* FIXME VOSSI */
            AL = 0x12;  /* function supported */

      } else if (BL == 0x33) {
            AH = 0x33;
            for (;;);   /* FIXME VOSSI */
            AL = 0x12;  /* function supported */

      } else if (BL == 0x34) {
            /* biosfn_enable_cursor_emulation(AL) */
            /* Not implemented yet - FIXME VOSSI */
            AL = 0x12;  /* function supported */

      } else if (BL == 0x35) {
            AH = 0x35;
            for (;;);   /* FIXME VOSSI */
            AL = 0x12;  /* function supported */

      } else if (BL == 0x36) {
            /* video refresh control */
            if (AL == 0) {
                  /* enable refresh - FIXME MARCEL */
            } else {
                  /* disable refresh - FIXME MARCEL */
                  /* effectively clears screen */
            }
            AL = 0x12;  /* function supported */

      } else {
#if 0       /* disable this on failure - FIXME MARCEL */
            for (;;);
#endif
      }
}

/*
 * VGA Function 13: Write string
 *
 * In:      AH    = 13h
 *    AL    = mode
 *     Bit0 = update cursor after writing
 *     Bit1 = strings contains character/attribute pairs
 *     Bit2-7     = reservered (0)
 *    BH    = page #
 *    BL    = attribute if AL bit1 not set
 *    DH    = row at which to start writing
 *    DL    = column at which to start writing
 *    CX    = length of string
 *    ES:BP = string
 *
 * Out:
 */
void
bios_10_13xx(struct regs *regs)
{
      unsigned char orig_x;
      unsigned char orig_y;
      unsigned short i;
      unsigned short offset;

#ifdef DEBUG_INT10
        dprintf("VGA Function 13: Write string.\n");
#endif
      /* Save old cursor position. */
      orig_x = var_get(curspos[BH].x);
      orig_y = var_get(curspos[BH].y);

      if (DH != 0xff) {
            /* Set cursor start position. */
            set_cursor_pos(BH, DL, DH);
      }

      offset = 0;
      for (i = 0; i < CX; i++) {
            unsigned char c, a;

            /* attributes included ? */
            if ((AL >> 1) & 1) {
                  c = get_byte(ES, (unsigned char *) (BP + offset++));
                  a = get_byte(ES, (unsigned char *) (BP + offset++));
            } else {
                  c = get_byte(ES, (unsigned char *) (BP + offset++));
                  a = BL;
            }
            write_teletype(c, BH, a, 1);
      }

      /* Restore old cursor position. */
      if (! (AL & 1)) {
            set_cursor_pos(BH, orig_x, orig_y);
      }
}

/*
 * VGA Function 1a: different sub-functions
 *
 * In:      AH    = 1ah
 *    AL    = sub-function #
 */

/* sub-function 00: get primary/secondary video adapter
 *
 * In:      AL    = 00h
 *
 * Out: AL  = 1ah (means VGA installed / function supported)
 *    BL    =           device code for adapter
 *    BH    = alternate device code for adapter
 */
void
bios_10_1a00(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1a: sub-function 00: get video adapter.\n");
#endif
      AX = 0x1a;
      BL = 0x08; /* color VGA */
      BH = 0x07; /* alternative monochrome VGA */
}

/*
 * VGA Function 1b: Get state information.
 */
void
bios_10_1bxx(struct regs *regs)
{
#ifdef DEBUG_INT10
        dprintf("VGA Function 1b: Get state information.\n");
#endif
      AL = 0x00;  /* Function *not* supported (yet) - FIXME VOSSI */
}

Generated by  Doxygen 1.6.0   Back to index