Merge branch 'console-dev'
[lunaix-os.git] / lunaix-os / kernel / tty / tty.c
1 #include <hal/io.h>
2 #include <klibc/string.h>
3 #include <lunaix/common.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/tty/console.h>
6 #include <lunaix/tty/tty.h>
7 #include <stdint.h>
8
9 vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR;
10
11 vga_attribute tty_theme_color = VGA_COLOR_BLACK;
12
13 #define TTY_CLEAR                                                              \
14     asm volatile("rep stosw" ::"D"(tty_vga_buffer),                            \
15                  "c"(TTY_HEIGHT * TTY_WIDTH),                                  \
16                  "a"(tty_theme_color)                                          \
17                  : "memory");
18
19 void
20 tty_init(void* vga_buf)
21 {
22     tty_vga_buffer = (vga_attribute*)vga_buf;
23
24     TTY_CLEAR
25
26     io_outb(0x3D4, 0x0A);
27     io_outb(0x3D5, (io_inb(0x3D5) & 0xC0) | 13);
28
29     io_outb(0x3D4, 0x0B);
30     io_outb(0x3D5, (io_inb(0x3D5) & 0xE0) | 15);
31 }
32
33 void
34 tty_set_theme(vga_attribute fg, vga_attribute bg)
35 {
36     tty_theme_color = (bg << 4 | fg) << 8;
37 }
38
39 size_t
40 tty_flush_buffer(char* data, size_t pos, size_t limit, size_t buf_size)
41 {
42     int x = 0, y = 0;
43
44     // Clear screen
45     TTY_CLEAR
46
47     int state = 0;
48     int g[2] = { 0, 0 };
49     vga_attribute current_theme = tty_theme_color;
50     while (1) {
51         size_t ptr = pos % buf_size;
52         if (pos == limit) {
53             break;
54         }
55         char chr = data[pos];
56         if (state == 0 && chr == '\x033') {
57             state = 1;
58         } else if (state == 1 && chr == '[') {
59             state = 2;
60         } else if (state > 1) {
61             if ('0' <= chr && chr <= '9') {
62                 g[state - 2] = (chr - '0') + g[state - 2] * 10;
63             } else if (chr == ';' && state == 2) {
64                 state = 3;
65             } else {
66                 if (g[0] == 39 && g[1] == 49) {
67                     current_theme = tty_theme_color;
68                 } else {
69                     current_theme = (g[1] << 4 | g[0]) << 8;
70                 }
71                 g[0] = 0;
72                 g[1] = 0;
73                 state = 0;
74             }
75         } else {
76             state = 0;
77             switch (chr) {
78                 case '\t':
79                     x += 4;
80                     break;
81                 case '\n':
82                     y++;
83                     // fall through
84                 case '\r':
85                     x = 0;
86                     break;
87                 case '\x08':
88                     x = x ? x - 1 : 0;
89                     *(tty_vga_buffer + x + y * TTY_WIDTH) =
90                       (current_theme | 0x20);
91                     break;
92                 default:
93                     *(tty_vga_buffer + x + y * TTY_WIDTH) =
94                       (current_theme | chr);
95                     (x)++;
96                     break;
97             }
98
99             if (x >= TTY_WIDTH) {
100                 x = 0;
101                 y++;
102             }
103             if (y >= TTY_HEIGHT) {
104                 y--;
105                 break;
106             }
107         }
108         pos++;
109     }
110     tty_set_cursor(x, y);
111     return pos;
112 }
113
114 void
115 tty_set_cursor(uint8_t x, uint8_t y)
116 {
117     if (x >= TTY_WIDTH || y >= TTY_HEIGHT) {
118         x = y = 0;
119     }
120     uint32_t pos = y * TTY_WIDTH + x;
121     io_outb(0x3D4, 14);
122     io_outb(0x3D5, pos / 256);
123     io_outb(0x3D4, 15);
124     io_outb(0x3D5, pos % 256);
125 }
126
127 void
128 tty_clear_line(int line_num)
129 {
130     asm volatile("rep stosw" ::"D"(tty_vga_buffer + line_num * TTY_WIDTH),
131                  "c"(TTY_WIDTH),
132                  "a"(tty_theme_color)
133                  : "memory");
134 }
135
136 void
137 tty_put_str_at(char* str, int x, int y)
138 {
139     char c;
140     while ((c = (*str)) && y < TTY_HEIGHT) {
141         *(tty_vga_buffer + x + y * TTY_WIDTH) = c | tty_theme_color;
142         x++;
143         if (x >= TTY_WIDTH) {
144             y++;
145             x = 0;
146         }
147         str++;
148     }
149 }