summaryrefslogtreecommitdiffstats
path: root/drivers/video/console/vgacon.c
blob: cad384a4bc346d8958b7ab17b7463272e6608f6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
	Low level VGA based console driver
*/

#include "string.h"
#include "video/vga.h"
#include "asm/io.h"

#define LIGHT_GREY_ON_BLACK \
	VGA_ENTRY_COLOR(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK)

static uint16_t *vga_vram_base;
static size_t vga_vram_size;
static size_t vga_cols;
static size_t vga_rows;
static uint8_t vga_attr;

static size_t cursor_x;
static size_t cursor_y;

void vgacon_init(void)
{
	vga_vram_base = (uint16_t *) VGA_VRAM_BC;
	vga_cols = 80;
	vga_rows = 25;
	vga_vram_size = vga_cols * vga_rows;
	vga_attr = LIGHT_GREY_ON_BLACK;

	cursor_x = 0;
	cursor_y = 0;
}

void vgacon_setattr(uint8_t attr)
{
	vga_attr = attr;
}

void vgacon_scroll(size_t lines)
{
	uint16_t vga_char = VGA_ENTRY(' ', vga_attr);
	size_t count = (vga_rows - lines) * vga_cols;
	memmove(vga_vram_base, vga_vram_base + vga_cols * lines, count * 2);
	for(; count < vga_vram_size; count++)
		vga_vram_base[count] = vga_char;
}

void vgacon_cls(void)
{
	vgacon_scroll(vga_rows);
}

static void putchar(char c)
{
	if(c == '\n') {
		cursor_x = 0;
		if(++cursor_y >= vga_rows) {
			vgacon_scroll(1);
			cursor_y--;
		}	
	}
	else {
		const size_t index = cursor_y * vga_cols + cursor_x;
		vga_vram_base[index] = VGA_ENTRY(c, vga_attr);

		if(++cursor_x >= vga_cols) {
			cursor_x = 0;
			if(++cursor_y >= vga_rows) {
				vgacon_scroll(1);
				cursor_y--;
			}
		}
	}
}

static void update_cursor()
{
	uint16_t pos = cursor_y * vga_cols + cursor_x;
	outb(VGA_CRTC_IC, VGA_CRTC_CURSOR_H);
	outb(VGA_CRTC_DC, (uint8_t) ((pos >> 8) & 0xFF));
	outb(VGA_CRTC_IC, VGA_CRTC_CURSOR_L);
	outb(VGA_CRTC_DC, (uint8_t) (pos & 0xFF));
}

void vgacon_putchar(char c)
{
	putchar(c);
	update_cursor();
}

void vgacon_write(const char *str, size_t size)
{
	size_t i;
	for(i = 0; i < size; i++)
		putchar(str[i]);
	update_cursor();
}

void vgacon_print(const char *str)
{
	vgacon_write(str, strlen(str));
}