Files
my-kern/kernel/drivers/vgascreen.c

139 lines
3.9 KiB
C

//
// Created by rick on 8/18/19.
//
#include <string.h>
#include <myke/drivers/vgascreen.h>
#include <myke/drivers/ports.h>
char *_vga_character_memory = (char *) VGA_CHARACTER_MEMORY_LOCATION;
int get_offset(int col, int row);
int get_cursor_offset();
void set_cursor_offset(int offset);
int get_offset_row(int offset);
int get_offset_col(int offset);
int print_char(char character, int col, int row, char attributes);
void vga_clear_screen() {
int size = VGA_COL_MAX * VGA_ROW_MAX;
for (int i = 0; i < size; ++i) {
_vga_character_memory[i * 2] = ' ';
_vga_character_memory[i * 2 + 1] = VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG);
}
set_cursor_offset(0);
}
void kprint_at(const char *message, int col, int row) {
int offset;
if (col > 0 && row > 0) {
offset = get_offset(col, row);
} else {
offset = get_cursor_offset();
row = get_offset_row(offset);
col = get_offset_col(offset);
}
int i = 0;
while (message[i] != 0) {
offset = print_char(message[i++], col, row, VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG));
row = get_offset_row(offset);
col = get_offset_col(offset);
}
}
void vga_kprint(const char *message) {
kprint_at(message, -1, -1);
}
int print_char(char character, int col, int row, char attributes) {
if (!attributes) attributes = VGA_WHITE | (VGA_BLACK < VGA_SHIFT_BG);
if (col >= VGA_COL_MAX || row > +VGA_ROW_MAX) {
_vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 2] = 'E';
_vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 1] = VGA_RED | (VGA_WHITE < VGA_SHIFT_BG);
return get_offset(col, row);
}
int offset;
if (col >= 0 && row >= 0) {
offset = get_offset(col, row);
} else {
offset = get_cursor_offset();
}
switch (character) {
case '\n':
row = get_offset_row(offset);
offset = get_offset(0, row + 1);
break;
case '\t':
col = (col + 4) & (~0b11);
if (col > VGA_COL_MAX) {
row = get_offset_row(offset);
offset = get_offset(0, row + 1);
} else {
offset = get_offset(col, row);
}
break;
case '\r':
row = get_offset_row(offset);
offset = get_offset(0, row);
break;
default:
_vga_character_memory[offset] = character;
_vga_character_memory[offset + 1] = attributes;
offset += 2;
break;
}
if (offset >= (VGA_COL_MAX * 2 * VGA_ROW_MAX)) {
memcpy(_vga_character_memory,
_vga_character_memory + (VGA_COL_MAX * 2),
(2 * VGA_COL_MAX * VGA_ROW_MAX) - (2 * VGA_COL_MAX));
for (int i = 0; i < VGA_COL_MAX; ++i) {
_vga_character_memory[get_offset(i, VGA_ROW_MAX - 1)] = ' ';
}
offset = get_offset(0, VGA_ROW_MAX - 1);
}
set_cursor_offset(offset);
return offset;
}
int get_cursor_offset() {
port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H);
int offset = ((int) port_byte_in(PORT_REG_SCREEN_DATA)) << 8;
port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L);
offset += port_byte_in(PORT_REG_SCREEN_DATA);
return offset * 2;
}
void set_cursor_offset(int offset) {
offset /= 2;
port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L);
port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset & 0xFF));
port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H);
port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset >> 8) & 0xFF);
}
int get_offset(int col, int row) {
return (row * VGA_COL_MAX + col) * 2;
}
int get_offset_row(int offset) {
return offset / (VGA_COL_MAX * 2);
}
int get_offset_col(int offset) {
return (offset - (get_offset_row(offset) * 2 * VGA_COL_MAX)) / 2;
}