k-chow/k/libvga.c

252 lines
8.0 KiB
C
Raw Normal View History

/*
* Copyright (c) LSE
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY LSE AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL LSE BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <k/compiler.h>
#include "libvga.h"
#include "io.h"
/*
** Use to save the VGA plane 2, which contains the text font,
** when we switch into graphic mode.
*/
static unsigned char libvga_txt_mode_font[320 * 200];
/*
** Registers value for graphic mode.
*/
static unsigned char libvga_regs_320x200x256[] = {
/* MISC */
0x63,
/* SEQ */
0x03, 0x01, 0x0F, 0x00, 0x0E,
/* CRTC */
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF,
/* GC */
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF,
/* AC */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00
};
/*
** Registers value for basic text mode.
*/
static unsigned char libvga_regs_80x25xtext[] = {
/* MISC */
0x67,
/* SEQ */
0x03, 0x00, 0x03, 0x00, 0x02,
/* CRTC */
0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x50,
0x9C, 0x0E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
0xFF,
/* GC */
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
0xFF,
/* AC */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x0C, 0x00, 0x0F, 0x08, 0x00
};
/*
** Basic Windows BITMAP pallet.
** This palette is automatically loaded when switching to mode 13h
*/
static unsigned int libvga_default_palette[256] = {
0x0, 0x800000, 0x8000, 0x808000,
0x80, 0x800080, 0x8080, 0xc0c0c0,
0xc0dcc0, 0xa6caf0, 0x402000, 0x602000,
0x802000, 0xa02000, 0xc02000, 0xe02000,
0x4000, 0x204000, 0x404000, 0x604000,
0x804000, 0xa04000, 0xc04000, 0xe04000,
0x6000, 0x206000, 0x406000, 0x606000,
0x806000, 0xa06000, 0xc06000, 0xe06000,
0x8000, 0x208000, 0x408000, 0x608000,
0x808000, 0xa08000, 0xc08000, 0xe08000,
0xa000, 0x20a000, 0x40a000, 0x60a000,
0x80a000, 0xa0a000, 0xc0a000, 0xe0a000,
0xc000, 0x20c000, 0x40c000, 0x60c000,
0x80c000, 0xa0c000, 0xc0c000, 0xe0c000,
0xe000, 0x20e000, 0x40e000, 0x60e000,
0x80e000, 0xa0e000, 0xc0e000, 0xe0e000,
0x40, 0x200040, 0x400040, 0x600040,
0x800040, 0xa00040, 0xc00040, 0xe00040,
0x2040, 0x202040, 0x402040, 0x602040,
0x802040, 0xa02040, 0xc02040, 0xe02040,
0x4040, 0x204040, 0x404040, 0x604040,
0x804040, 0xa04040, 0xc04040, 0xe04040,
0x6040, 0x206040, 0x406040, 0x606040,
0x806040, 0xa06040, 0xc06040, 0xe06040,
0x8040, 0x208040, 0x408040, 0x608040,
0x808040, 0xa08040, 0xc08040, 0xe08040,
0xa040, 0x20a040, 0x40a040, 0x60a040,
0x80a040, 0xa0a040, 0xc0a040, 0xe0a040,
0xc040, 0x20c040, 0x40c040, 0x60c040,
0x80c040, 0xa0c040, 0xc0c040, 0xe0c040,
0xe040, 0x20e040, 0x40e040, 0x60e040,
0x80e040, 0xa0e040, 0xc0e040, 0xe0e040,
0x80, 0x200080, 0x400080, 0x600080,
0x800080, 0xa00080, 0xc00080, 0xe00080,
0x2080, 0x202080, 0x402080, 0x602080,
0x802080, 0xa02080, 0xc02080, 0xe02080,
0x4080, 0x204080, 0x404080, 0x604080,
0x804080, 0xa04080, 0xc04080, 0xe04080,
0x6080, 0x206080, 0x406080, 0x606080,
0x806080, 0xa06080, 0xc06080, 0xe06080,
0x8080, 0x208080, 0x408080, 0x608080,
0x808080, 0xa08080, 0xc08080, 0xe08080,
0xa080, 0x20a080, 0x40a080, 0x60a080,
0x80a080, 0xa0a080, 0xc0a080, 0xe0a080,
0xc080, 0x20c080, 0x40c080, 0x60c080,
0x80c080, 0xa0c080, 0xc0c080, 0xe0c080,
0xe080, 0x20e080, 0x40e080, 0x60e080,
0x80e080, 0xa0e080, 0xc0e080, 0xe0e080,
0xc0, 0x2000c0, 0x4000c0, 0x6000c0,
0x8000c0, 0xa000c0, 0xc000c0, 0xe000c0,
0x20c0, 0x2020c0, 0x4020c0, 0x6020c0,
0x8020c0, 0xa020c0, 0xc020c0, 0xe020c0,
0x40c0, 0x2040c0, 0x4040c0, 0x6040c0,
0x8040c0, 0xa040c0, 0xc040c0, 0xe040c0,
0x60c0, 0x2060c0, 0x4060c0, 0x6060c0,
0x8060c0, 0xa060c0, 0xc060c0, 0xe060c0,
0x80c0, 0x2080c0, 0x4080c0, 0x6080c0,
0x8080c0, 0xa080c0, 0xc080c0, 0xe080c0,
0xa0c0, 0x20a0c0, 0x40a0c0, 0x60a0c0,
0x80a0c0, 0xa0a0c0, 0xc0a0c0, 0xe0a0c0,
0xc0c0, 0x20c0c0, 0x40c0c0, 0x60c0c0,
0x80c0c0, 0xa0c0c0, 0xfffbf0, 0xa0a0a4,
0x808080, 0xff0000, 0xff00, 0xffff00,
0xff, 0xff00ff, 0xffff, 0xffffff
};
static void libvga_write_regs(unsigned char *regs)
{
unsigned int i;
unsigned int a;
/* write the MISC register */
outb(VGA_MISC_WRITE, *regs);
regs++;
/* write SEQ registers */
for (i = 0; i < VGA_NUM_SEQ_REGS; i++) {
outb(VGA_SEQ_INDEX, i);
outb(VGA_SEQ_DATA, *regs);
regs++;
}
/* write CRTC registers */
outb(VGA_CRTC_INDEX, 0x03);
a = inb(VGA_CRTC_DATA);
outb(VGA_CRTC_DATA, a | 0x80);
outb(VGA_CRTC_INDEX, 0x11);
a = inb(VGA_CRTC_DATA);
outb(VGA_CRTC_DATA, a & ~0x80);
regs[0x03] |= 0x80;
regs[0x11] &= ~0x80;
for (i = 0; i < VGA_NUM_CRTC_REGS; i++) {
outb(VGA_CRTC_INDEX, i);
outb(VGA_CRTC_DATA, *regs);
regs++;
}
/* write GC registers */
for (i = 0; i < VGA_NUM_GC_REGS; i++) {
outb(VGA_GC_INDEX, i);
outb(VGA_GC_DATA, *regs);
regs++;
}
/* write AC registers */
inb(VGA_INSTAT_READ);
for (i = 0; i < VGA_NUM_AC_REGS; i++) {
outb(VGA_AC_INDEX, i);
outb(VGA_AC_WRITE, *regs);
regs++;
}
inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX, 0x20);
/* write the default palette to the DAC */
outb(VGA_DAC_MASK, 0xFF);
libvga_set_palette(libvga_default_palette, array_size(libvga_default_palette));
}
void libvga_set_palette(unsigned int *new_palette, size_t size)
{
outb(VGA_DAC_WRITE_INDEX, 0);
for (size_t i = 0; i < size; i++) {
outb(VGA_DAC_DATA, ((new_palette[i] >> 16) >> 2) & 0xFF);
outb(VGA_DAC_DATA, ((new_palette[i] >> 8) >> 2) & 0xFF);
outb(VGA_DAC_DATA, ((new_palette[i]) >> 2) & 0xFF);
}
}
char *libvga_get_framebuffer(void)
{
unsigned int mmap_select;
outb(VGA_GC_INDEX, 6);
mmap_select = inb(VGA_GC_DATA);
mmap_select >>= 2;
mmap_select &= 3;
switch (mmap_select) {
case 0:
case 1:
return (char *)0xA0000;
case 2:
return (char *)0xB0000;
case 3:
return (char *)0xB8000;
}
return (char *)0;
}
void libvga_switch_mode13h(void)
{
libvga_write_regs(libvga_regs_320x200x256);
// plane 2 is now map in the memory, save it
char *vram = libvga_get_framebuffer();
for (size_t i = 0; i < array_size(libvga_txt_mode_font); i++)
libvga_txt_mode_font[i] = vram[i];
}
void libvga_switch_mode3h(void)
{
// restore the VGA plane 2 to the text font
char *vram = libvga_get_framebuffer();
for (size_t i = 0; i < array_size(libvga_txt_mode_font); i++)
vram[i] = libvga_txt_mode_font[i];
libvga_write_regs(libvga_regs_80x25xtext);
}