vulcanos/kernel/drivers/tty.c

154 lines
3.7 KiB
C

#include "tty.h"
#include "../libc/string.h"
#include "ports.h"
#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer
// Also define a 2 byte pointer because cells are 16 bits wide
#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR)
#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
static uint32_t fb_col = 1; // X
static uint32_t fb_row = 0; // Y
void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) {
uint8_t *fb = VGA_PTR;
fb[i*2] = c;
fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F);
}
void move_cursor(uint16_t pos) {
outb(VGA_CMD_PORT, VGA_HIGH_BYTE);
outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF));
outb(VGA_CMD_PORT, VGA_LOW_BYTE);
outb(VGA_DATA_PORT, pos & 0x00FF);
}
void cursor_adv() { // TODO: specify number of adv. with a parameter
if(fb_col < VGA_WIDTH - 1)
fb_col++;
else
newline();
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void cursor_prev() {
if(fb_col == 0) {
if(fb_row == 0)
return; // If first row do not do anything
fb_col = VGA_WIDTH - 1;
fb_row--;
} else
fb_col--;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void backspace() {
uint16_t pos;
uint8_t c = ' ';
fb_col--;
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, c, WHITE, BLACK);
}
void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) {
uint16_t pos;
for(uint32_t i = 0; i < len; i++) {
uint8_t c = buf[i];
if(c == '\n' || c == '\r')
newline();
else if(c == '\t')
tab();
else {
pos = fb_col + (fb_row * VGA_WIDTH);
write_cell(pos, (uint8_t)c, fg, bg);
cursor_adv();
}
}
}
void kprint(uint8_t *buf) {
kprint_c(buf, strlen(buf), WHITE, BLACK);
}
void kprint_dec(uint32_t num) {
if(num == 0) {
uint8_t *buf = (uint8_t*)'0';
kprint_c(buf, strlen(buf), WHITE, BLACK);;
return;
}
int32_t acc = num;
uint8_t c[32];
int32_t i = 0;
while(acc > 0) {
c[i] = '0' + acc%10;
acc /= 10;
i++;
}
c[i] = 0;
uint8_t c2[32];
c2[i--] = 0;
uint32_t j = 0;
while(i >= 0)
c2[i--] = c[j++];
kprint(c2);
}
void init_prompt() {
uint8_t user[64], hostname[64];
#ifdef DEFAULT_USER
strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER));
#else
#error "-DDEFAULT_USER flag not set"
#endif
#ifdef DEFAULT_HOSTNAME
strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME));
#else
#error "-DDEFAULT_HOSTNAME flag not set"
#endif
newline();
kprint_c(user, strlen(user), LIGHT_CYAN, BLACK);
kprint_c((uint8_t*)"@", 1, LIGHT_RED, BLACK);
kprint_c(hostname, strlen(hostname), LIGHT_MAGENTA, BLACK);
kprint_c((uint8_t*)" #> ", 4, LIGHT_BLUE, BLACK);
}
void clear_prompt() {
fb_col = 1;
fb_row = 0;
for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++)
write_cell(i, ' ', WHITE, BLACK);
move_cursor(0);
}
void clear_row(uint8_t row) {
for(size_t i = 0; i < VGA_WIDTH; i++)
write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK);
}
void scroll() {
uint16_t *fb = UVGA_PTR;
memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1));
clear_row(VGA_HEIGHT - 1);
}
void newline() {
if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it
fb_row++;
else // Otherwise scroll framebuffer
scroll();
fb_col = 1;
move_cursor(fb_col + (fb_row * VGA_WIDTH));
}
void tab() {
for(uint8_t i = 0; i < 4; i++)
cursor_adv(); // Increment cursor 4 times
}