matos/drivers/vga.c
Mathieu Maret ea9e5f7f23 Fix cursor
2018-11-15 13:29:05 +01:00

219 lines
4.4 KiB
C

#include "vga.h"
#include "io.h"
#include "klibc.h"
static uint vgaBgColor;
static uint vgaColor;
static int line, col;
int VGASetup(uint bgColor, uint color)
{
vgaBgColor = bgColor;
vgaColor = color;
clearScreen(bgColor);
line = 0;
col = 0;
return 0;
}
void clearScreen(uint bgColor)
{
volatile short *vga = (short *)VGA_ADDR;
long int colorAttr = bgColor << 12;
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
vga[i] = colorAttr;
}
}
void printInt(int integer)
{
char num[sizeof(int) *
3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) =
// 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3)
int i = 0, k = 0;
if (integer < 0) {
printChar('-');
}
if (integer == 0) {
num[i++] = 0;
}
while (integer != 0) {
int digit = integer % 10;
num[i++] = (digit > 0) ? digit : -digit;
integer = integer / 10;
}
for (k = i - 1; k >= 0; k--) {
printChar(num[k] + '0');
}
}
void printIntDetails(int integer, uint color, uint bgColor, int startX, int startY)
{
char num[sizeof(int) *
3]; // int max is 2^(sizeof(int)*8) which is (2^3)^(sizeof(int)*8/3) =
// 8^(sizeof(int)*8/3) ~ 10^(sizeof(int)*8/3)
int x = startX;
int i = 0, k = 0;
if (integer < 0) {
printCharDetails('-', color, bgColor, x++, startY);
}
if (integer == 0) {
num[i++] = 0;
}
while (integer != 0) {
int digit = integer % 10;
num[i++] = (digit > 0) ? digit : -digit;
integer = integer / 10;
}
for (k = i - 1; k >= 0; k--) {
printCharDetails(num[k] + '0', color, bgColor, x++, startY);
}
}
void printCharDetails(const char str, uint color, uint bgColor, int startX, int startY)
{
volatile short *vga = (short *)VGA_ADDR;
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
vga[VGA_WIDTH * startY + startX] = colorAttr | str;
}
void vgaScrollUp(void)
{
long int colorAttr = vgaBgColor << 12;
volatile short *vga = (short *)VGA_ADDR;
for (int i = 1; i < VGA_HEIGHT - 1;
i++) { // last line is status line. Do not scroll it
memcpy((void *)&vga[VGA_WIDTH * (i - 1)], (void *)&vga[VGA_WIDTH * i],
VGA_WIDTH * sizeof(short));
}
for (int i = 0; i < VGA_WIDTH; i++) {
vga[(VGA_HEIGHT - 2) * VGA_WIDTH + i] = colorAttr;
}
}
void vprintf(const char *format, va_list ap)
{
int i = 0;
while (format[i] != '\0') {
switch (format[i]) {
case '%':
switch (format[i + 1]) {
case 'i':
case 'd': {
int d = va_arg(ap, int);
printInt(d);
break;
}
case 'c': {
int c = va_arg(ap, int);
printChar((char)c);
break;
}
case 's': {
char *str = va_arg(ap, char *);
if (!str)
str = "[NULL STR]";
printString(str);
break;
}
case '%':
printChar('%');
break;
}
i++;
break;
default:
printChar(format[i]);
}
i++;
}
}
void printf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
}
void printString(const char *str)
{
while (*str) {
printChar(*(str++));
}
}
void printChar(const char str)
{
if (str == '\n') {
line++;
col = 0;
if (line >= VGA_HEIGHT - 1) {
vgaScrollUp();
line--;
}
} else if (str == '\r') {
col = 0;
} else if (str == '\b') {
col--;
if (col < 0) {
col = VGA_WIDTH - 1;
line--;
}
printCharDetails(' ', vgaColor, vgaBgColor, col, line);
} else {
printCharDetails(str, vgaColor, vgaBgColor, col++, line);
if (col == VGA_WIDTH) {
col = 0;
line++;
}
if (line >= VGA_HEIGHT - 1) {
vgaScrollUp();
line--;
}
}
cursorMove(col, line);
}
void printStringDetails(const char *str, uint color, uint bgColor, int startX, int startY)
{
volatile short *vga = (short *)VGA_ADDR;
int i = 0;
long int colorAttr = (bgColor << 4 | (color & 0x0f)) << 8;
while (*str) {
vga[VGA_WIDTH * startY + startX + i] = colorAttr | *str;
str++;
i++;
}
}
void cursorEnable(uint8_t cursor_start, uint8_t cursor_end)
{
outb(0x3D4, 0x0A);
outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);
outb(0x3D4, 0x0B);
outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
}
void cursorDisable(void)
{
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
}
void cursorMove(int x, int y)
{
volatile short *vga = (short *)VGA_ADDR;
long int colorAttr = (vgaBgColor << 4 | (vgaColor & 0x0f)) << 8;
uint16_t pos = y * VGA_WIDTH + x;
vga[pos] = colorAttr;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}