reorganize source
[com32] / src / kern / contty.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2023  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include "contty.h"
22 #include "serial.h"
23 #include "asmops.h"
24 #include "config.h"
25
26 #define VIRT_ROWS       200
27
28 #define NCOLS           80
29 #define NROWS           25
30 #define TEXT_ADDR       ((char*)0xb8000)
31
32 #define CRTC_ADDR       0x3d4
33 #define CRTC_DATA       0x3d5
34
35 #define CRTC_REG_CURSTART       0x0a
36 #define CRTC_REG_CUREND         0x0b
37 #define CRTC_REG_START_H        0x0c
38 #define CRTC_REG_START_L        0x0d
39 #define CRTC_REG_CURLOC_H       0x0e
40 #define CRTC_REG_CURLOC_L       0x0f
41
42 #define VMEM_CHAR(c, attr) \
43         (((uint16_t)(c) & 0xff) | ((uint16_t)(attr) << 8))
44
45 static void scroll(void);
46 static void crtc_cursor(int x, int y);
47 static void crtc_getcursor(int *x, int *y);
48 static void crtc_setstart(int y);
49 static int crtc_getstart(void);
50 static inline unsigned char crtc_read(int reg);
51 static inline void crtc_write(int reg, unsigned char val);
52
53 static int cursor_x, cursor_y;
54 static unsigned char txattr = 0x07;
55 static int start_line;
56 static unsigned char cy0, cy1;
57 static int curvis;
58 static int scr_on = 1;
59
60
61 int con_init(void)
62 {
63 #ifdef CON_SERIAL
64         ser_open(1, 9600, SER_8N1);
65 #endif
66
67 #ifdef CON_TEXTMODE
68         cy0 = crtc_read(CRTC_REG_CURSTART);
69         curvis = cy0 & 0x20 ? 1 : 0;
70         cy0 &= 0x1f;
71         cy1 = crtc_read(CRTC_REG_CUREND) & 0x1f;
72
73         start_line = crtc_getstart();
74         crtc_getcursor(&cursor_x, &cursor_y);
75         con_show_cursor(1);
76         scr_on = 1;
77 #endif
78
79         return 0;
80 }
81
82 void con_scr_enable(void)
83 {
84         scr_on = 1;
85 }
86
87 void con_scr_disable(void)
88 {
89         scr_on = 0;
90 }
91
92 void con_show_cursor(int show)
93 {
94 #ifdef CON_TEXTMODE
95         unsigned char val = cy0 & 0x1f;
96         if(!show) {
97                 val |= 0x20;
98         }
99         crtc_write(CRTC_REG_CURSTART, val);
100         curvis = show;
101 #endif
102 }
103
104 void con_cursor(int x, int y)
105 {
106 #ifdef CON_TEXTMODE
107         cursor_x = x;
108         cursor_y = y;
109         crtc_cursor(x, y);
110 #endif
111 }
112
113 void con_curattr(int shape, int blink)
114 {
115 #ifdef CON_TEXTMODE
116         unsigned char start;
117         cy0 = (shape == CON_CURSOR_LINE) ? 0xd : 0;
118         cy1 = 0xe;
119
120         start = cy0;
121         if(curvis) {
122                 start |= 0x20;
123         }
124
125         crtc_write(CRTC_REG_CURSTART, start);
126         crtc_write(CRTC_REG_CUREND, cy0);
127 #endif
128 }
129
130 void con_fgcolor(int c)
131 {
132         txattr = (txattr & 0xf0) | c;
133 }
134
135 void con_bgcolor(int c)
136 {
137         txattr = (txattr & 0x0f) | (c << 4);
138 }
139
140 void con_setattr(unsigned char attr)
141 {
142         txattr = attr;
143 }
144
145 unsigned char con_getattr(void)
146 {
147         return txattr;
148 }
149
150 void con_clear(void)
151 {
152 #ifdef CON_TEXTMODE
153         memset16(TEXT_ADDR, VMEM_CHAR(' ', txattr), NCOLS * NROWS);
154
155         start_line = 0;
156         crtc_setstart(0);
157
158         cursor_x = cursor_y = 0;
159         crtc_cursor(0, 0);
160 #endif
161 }
162
163 static inline void linefeed(void)
164 {
165         if(++cursor_y >= NROWS) {
166                 scroll();
167                 --cursor_y;
168         }
169 }
170
171 void con_putchar(int c)
172 {
173 #ifdef CON_TEXTMODE
174         if(scr_on) {
175                 switch(c) {
176                 case '\n':
177                         linefeed();
178                 case '\r':
179                         cursor_x = 0;
180                         crtc_cursor(cursor_x, cursor_y);
181                         break;
182
183                 case '\t':
184                         cursor_x = (cursor_x & 0x7) + 8;
185                         if(cursor_x >= NCOLS) {
186                                 linefeed();
187                                 cursor_x = 0;
188                         }
189                         crtc_cursor(cursor_x, cursor_y);
190                         break;
191
192                 case '\b':
193                         if(cursor_x > 0) cursor_x--;
194                         con_putchar_scr(cursor_x, cursor_y, ' ');
195                         crtc_cursor(cursor_x, cursor_y);
196                         break;
197
198                 default:
199                         con_putchar_scr(cursor_x, cursor_y, c);
200
201                         if(++cursor_x >= NCOLS) {
202                                 linefeed();
203                                 cursor_x = 0;
204                         }
205                         crtc_cursor(cursor_x, cursor_y);
206                 }
207         }
208 #endif
209
210 #ifdef CON_SERIAL
211         ser_putchar(c);
212 #endif
213 }
214
215 void con_putchar_scr(int x, int y, int c)
216 {
217 #ifdef CON_TEXTMODE
218         uint16_t *ptr = (uint16_t*)TEXT_ADDR;
219         ptr[(y + start_line) * NCOLS + x] = VMEM_CHAR(c, txattr);
220 #endif
221 }
222
223 int con_printf(int x, int y, const char *fmt, ...)
224 {
225 #ifdef CON_TEXTMODE
226         va_list ap;
227         char buf[81];
228         char *ptr = buf;
229
230         va_start(ap, fmt);
231         vsnprintf(buf, 80, fmt, ap);
232         va_end(ap);
233
234         while(*ptr && x < 80) {
235                 con_putchar_scr(x++, y, *ptr++);
236         }
237         return ptr - buf;
238 #else
239         return 0;
240 #endif
241 }
242
243 static void scroll(void)
244 {
245         int new_line;
246
247         if(++start_line > VIRT_ROWS - NROWS) {
248                 /* The bottom of the visible range reached the end of our text buffer.
249                  * Copy the rest of the lines to the top and reset start_line.
250                  */
251                 memcpy(TEXT_ADDR, TEXT_ADDR + start_line * NCOLS, (NROWS - 1) * NCOLS * 2);
252                 start_line = 0;
253         }
254
255         /* clear the next line that will be revealed by scrolling */
256         new_line = start_line + NROWS - 1;
257         memset16(TEXT_ADDR + new_line * NCOLS * 2, VMEM_CHAR(' ', txattr), NCOLS);
258         crtc_setstart(start_line);
259 }
260
261 static void crtc_cursor(int x, int y)
262 {
263         unsigned int addr;
264
265         addr = (y + start_line) * NCOLS + x;
266
267         crtc_write(CRTC_REG_CURLOC_L, addr);
268         crtc_write(CRTC_REG_CURLOC_H, addr >> 8);
269 }
270
271 static void crtc_getcursor(int *x, int *y)
272 {
273         unsigned int addr;
274
275         addr = crtc_read(CRTC_REG_CURLOC_L);
276         addr |= (unsigned int)crtc_read(CRTC_REG_CURLOC_H) << 8;
277
278         *y = addr / NCOLS - start_line;
279         *x = addr % NCOLS;
280 }
281
282 static void crtc_setstart(int y)
283 {
284         unsigned int addr = y * NCOLS;
285
286         crtc_write(CRTC_REG_START_L, addr);
287         crtc_write(CRTC_REG_START_H, addr >> 8);
288 }
289
290 static int crtc_getstart(void)
291 {
292         unsigned int addr;
293
294         addr = crtc_read(CRTC_REG_START_L);
295         addr |= (unsigned int)crtc_read(CRTC_REG_START_H) << 8;
296
297         return addr / NCOLS;
298 }
299
300 static inline unsigned char crtc_read(int reg)
301 {
302         outp(CRTC_ADDR, reg);
303         return inp(CRTC_DATA);
304 }
305
306 static inline void crtc_write(int reg, unsigned char val)
307 {
308         outp(CRTC_ADDR, reg);
309         outp(CRTC_DATA, val);
310 }