Files
novaos/kernel/arch/tty.c

132 lines
2.7 KiB
C

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/tty.h>
#include "vga.h"
#include "io.h"
/* I/O ports */
#define VGA_COMMAND_PORT 0x3D4
#define VGA_DATA_PORT 0x3D5
/* I/O port commands */
#define VGA_HIGH_BYTE_COMMAND 14
#define VGA_LOW_BYTE_COMMAND 15
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000;
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_colour;
static struct vga_entry* terminal_buffer;
struct vga_entry {
char c;
unsigned char colour;
} __attribute__((packed));
void terminal_set_colour(uint8_t colour)
{
terminal_colour = colour;
}
void terminal_clear(void)
{
for (size_t y = 0; y < VGA_HEIGHT; y++)
for (size_t x = 0; x < VGA_WIDTH; x++)
terminal_write_cell((y * VGA_WIDTH) + x, ' ');
terminal_move_cursor(0);
}
void terminal_initialize(void)
{
terminal_row = 0;
terminal_column = 0;
terminal_buffer = (struct vga_entry*) VGA_MEMORY;
terminal_set_colour(vga_entry_colour(VGA_COLOUR_LIGHT_GREY, VGA_COLOUR_BLACK));
terminal_clear();
}
void terminal_move_cursor(unsigned short pos)
{
if (terminal_row >= VGA_HEIGHT)
terminal_scroll_screen();
outb(VGA_COMMAND_PORT, VGA_HIGH_BYTE_COMMAND);
outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF));
outb(VGA_COMMAND_PORT, VGA_LOW_BYTE_COMMAND);
outb(VGA_DATA_PORT, pos & 0x00FF);
}
inline size_t terminal_get_pos(void)
{return (terminal_row * VGA_WIDTH) + terminal_column;}
void terminal_write_cell(unsigned int i, char c)
{
struct vga_entry entry;
entry.c = c;
entry.colour = terminal_colour;
terminal_buffer[i] = entry;
}
void terminal_write_character(unsigned int i, char c)
{
switch(c) {
case '\n':
terminal_row += 1;
__attribute__((fallthrough));
case '\r':
terminal_column = 0;
terminal_move_cursor(terminal_get_pos());
break;
default:
terminal_write_cell(i, c);
terminal_column += 1;
if (terminal_column >= VGA_WIDTH) {
terminal_column = 0;
terminal_row += 1;
}
terminal_move_cursor(terminal_get_pos());
}
}
void terminal_write(const char* buf, size_t len)
{
for (size_t i = 0; i < len; i++)
terminal_write_character(terminal_get_pos(), buf[i]);
}
void terminal_writestring(const char* buf)
{
terminal_write(buf, strlen(buf));
}
void terminal_scroll_screen(void)
{
size_t y, x;
for (y = 0; y < VGA_HEIGHT -1; y++) {
for (x = 0; x < VGA_WIDTH; x++) {
terminal_buffer[(y * VGA_WIDTH) + x] =
terminal_buffer[((y + 1) * VGA_WIDTH) + x];
}
}
for (x = 0; x < VGA_WIDTH; x++)
terminal_write_cell(((VGA_HEIGHT - 1) * VGA_WIDTH) + x, ' ');
terminal_row -= 1;
terminal_column = 0;
terminal_move_cursor(terminal_get_pos());
}