151 lines
4.1 KiB
C
151 lines
4.1 KiB
C
//
|
|
// Created by rick on 8/18/19.
|
|
//
|
|
|
|
#include <string.h>
|
|
|
|
#include <myke/drivers/ports.h>
|
|
#include <myke/drivers/vgascreen.h>
|
|
#include <myke/libk/kprint.h>
|
|
#include <myke/util/init.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;
|
|
}
|
|
|
|
void vga_init() {
|
|
vga_clear_screen();
|
|
kprint_register(vga_kprint);
|
|
}
|
|
|
|
INIT_FUNCTION(100) = {
|
|
.name = "vga",
|
|
.stage = INIT_STAGE_EARLY_BOOT_0,
|
|
.init = vga_init,
|
|
}; |