- Implemented first time functions.
[planlOS.git] / system / kernel / sys / terminal.c
blobadb3377a069a5f07dab233fa8026715a2c46d7b4
1 /*
2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "sys/terminal.h"
23 #include "ke/debug.h"
24 #include "ke/level.h"
25 #include "fs/request.h"
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
31 static char *termnames[12] =
33 "tty0",
34 "tty1",
35 "tty2",
36 "tty3",
37 "tty4",
38 "tty5",
39 "tty6",
40 "tty7",
41 "gfx0",
42 "gfx1",
43 "gfx2",
44 "gfx3",
46 static SysTextTerminal textterms[8];
47 static SysGfxTerminal gfxterms[4];
49 static int currentterm = 0;
51 static int screenwidth = 80;
52 static int screenheight = 25;
54 static char *vidmem = (char*)0xC00B8000;
56 static KeSpinlock terminallock;
58 void keTerminalInitialized(void);
60 static int control_pressed = 0;
62 static void sysTerminalScroll(SysTextTerminal *terminal, int lines, int screen)
64 if (screen)
66 memmove(vidmem, vidmem + lines * 160, (25 - lines) * 160);
67 memset(vidmem + (25 - lines) * 160, 0, lines * 160);
69 memmove(terminal->screendata, terminal->screendata + lines * 160, (25 - lines) * 160);
70 memset(terminal->screendata + (25 - lines) * 160, 0, lines * 160);
71 terminal->y -= lines;
74 static void sysTerminalWriteChar(SysTextTerminal *terminal, char c, int screen)
76 if (terminal->x >= 80)
78 terminal->x = 0;
79 terminal->y++;
80 if (terminal->y == 25)
81 sysTerminalScroll(terminal, 1, screen);
83 int position = (screenwidth * terminal->y + terminal->x) * 2;
84 switch (c)
86 case '\n':
87 terminal->y++;
88 terminal->x = 0;
89 if (terminal->y == 25)
90 sysTerminalScroll(terminal, 1, screen);
91 break;
92 case '\r':
93 terminal->x = 0;
94 break;
95 case '\t':
96 sysTerminalWriteChar(terminal, ' ', screen);
97 while (terminal->x % 7)
98 sysTerminalWriteChar(terminal, ' ', screen);
99 break;
100 default:
101 terminal->screendata[position] = c;
102 terminal->screendata[position + 1] = (terminal->brightfg << 3) + (terminal->bgcolor << 4) + terminal->fgcolor;
103 if (screen)
105 vidmem[position] = c;
106 vidmem[position + 1] = (terminal->brightfg << 3) + (terminal->bgcolor << 4) + terminal->fgcolor;
108 terminal->x++;
109 break;
113 static int sysTerminalWriteEscape(SysTextTerminal *terminal, char *data, int size, int screen)
115 // Escape character
116 int written = 1;
117 data++;
118 size--;
119 if (!size) return written;
120 // [
121 switch (*data)
123 case '[':
124 size--;
125 data++;
126 written++;
127 if (!size) return written;
128 break;
129 default:
130 return written;
132 // Parameters
133 int paramcount = 0;
134 int parameters[10] = {0};
135 while (isdigit(*data))
137 parameters[paramcount] = *data - '0';
138 data++;
139 size--;
140 written++;
141 if (!size) return written;
142 if (!size) return written;
143 // Read in number
144 while (isdigit(*data))
146 parameters[paramcount] = parameters[paramcount] * 10 + *data - '0';
147 data++;
148 size--;
149 written++;
150 if (!size) return written;
152 paramcount++;
153 if (paramcount == 10) return written;
154 if (*data == ';')
156 data++;
157 size--;
158 written++;
159 if (!size) return written;
160 continue;
163 // Command
164 int i;
165 switch (*data)
167 case 'J':
168 if ((paramcount >= 1) && (parameters[0] == 2))
170 // Clear screen
171 memset(terminal->screendata, 0, screenwidth * screenheight * 2);
172 if (screen)
174 memset(vidmem, 0, screenwidth * screenheight * 2);
177 break;
178 case 'm':
179 // Set parameters
180 for (i = 0; i < 10; i++)
182 if (i == paramcount) break;
183 switch (parameters[i])
185 case 1: // Bright
186 terminal->brightfg = 1;
187 break;
188 case 2: // Dim
189 terminal->brightfg = 0;
190 break;
191 case 30: // Black
192 terminal->fgcolor = 0;
193 break;
194 case 31: // Red
195 terminal->fgcolor = 4;
196 break;
197 case 32: // Green
198 terminal->fgcolor = 2;
199 break;
200 case 33: // Yellow
201 terminal->fgcolor = 6;
202 break;
203 case 34: // Blue
204 terminal->fgcolor = 1;
205 break;
206 case 35: // Magenta
207 terminal->fgcolor = 5;
208 break;
209 case 36: // Cyan
210 terminal->fgcolor = 3;
211 break;
212 case 37: // White
213 terminal->fgcolor = 7;
214 break;
215 case 40: // Black
216 terminal->bgcolor = 0;
217 break;
218 case 41: // Red
219 terminal->bgcolor = 4;
220 break;
221 case 42: // Green
222 terminal->bgcolor = 2;
223 break;
224 case 43: // Yellow
225 terminal->bgcolor = 6;
226 break;
227 case 44: // Blue
228 terminal->bgcolor = 1;
229 break;
230 case 45: // Magenta
231 terminal->bgcolor = 5;
232 break;
233 case 46: // Cyan
234 terminal->bgcolor = 3;
235 break;
236 case 47: // White
237 terminal->bgcolor = 7;
238 break;
241 break;
242 case 'H':
243 // Set cursor position
244 if (paramcount == 2)
246 terminal->x = parameters[1] - 1;
247 if (terminal->x < 0) terminal->x = 0;
248 if (terminal->x >= screenwidth) terminal->x = screenwidth - 1;
249 terminal->y = parameters[0] - 1;
250 if (terminal->y < 0) terminal->y = 0;
251 if (terminal->y >= screenheight) terminal->y = screenheight - 1;
253 break;
255 return written + 1;
258 static void sysTerminalWrite(SysTextTerminal *terminal, char *data, int size, int screen)
260 int i;
261 for (i = 0; i < size; i++)
263 if (data[i] == 033)
265 i += sysTerminalWriteEscape(terminal, data + i, size - i, screen);
266 i--;
268 else
270 sysTerminalWriteChar(terminal, data[i], screen);
275 static int sysTerminalRequest(struct FsDeviceFile *file, FsRequest *request)
277 SysTextTerminal *terminal = (SysTextTerminal*)file;
278 int index = ((uintptr_t)terminal - (uintptr_t)textterms) / sizeof(SysTextTerminal);
280 switch (request->type)
282 case FS_REQUEST_READ:
284 KeExecLevel oldlevel = keSetExecutionLevel(KE_LEVEL_HIGH);
285 keSetExecutionLevel(KE_LEVEL_HIGH);
286 keLockSpinlock(&terminallock);
287 if (!terminal->requestcount && (terminal->inputbuffer_pos >= (int)request->bufferlength))
289 // Directly copy from the buffer
290 memcpy(request->buffer, terminal->inputbuffer, request->bufferlength);
291 memmove(terminal->inputbuffer, terminal->inputbuffer + request->bufferlength,
292 terminal->inputbuffer_pos - request->bufferlength);
293 terminal->inputbuffer_pos -= request->bufferlength;
294 request->return_value = request->bufferlength;
295 fsFinishRequest(request);
297 else
299 // Put the request into the queue
300 terminal->requests = realloc(terminal->requests, sizeof(FsRequest*) * (terminal->requestcount + 1));
301 terminal->requests[terminal->requestcount] = request;
302 terminal->requestcount++;
304 keUnlockSpinlock(&terminallock);
305 keSetExecutionLevel(oldlevel);
307 break;
308 case FS_REQUEST_WRITE:
310 KeExecLevel oldlevel = keSetExecutionLevel(KE_LEVEL_HIGH);
311 keLockSpinlock(&terminallock);
312 sysTerminalWrite(terminal, request->buffer, request->bufferlength,
313 index == currentterm);
314 keUnlockSpinlock(&terminallock);
315 keSetExecutionLevel(oldlevel);
316 request->return_value = request->bufferlength;
317 fsFinishRequest(request);
319 break;
320 case FS_REQUEST_IOCTLSIZE:
321 if (request->offset == 0x10)
323 request->return_value = 8;
324 fsFinishRequest(request);
325 return 0;
327 return -1;
328 case FS_REQUEST_IOCTL:
329 if (request->offset == 0x10)
331 uint16_t *data = request->buffer;
332 if (currentterm < 8)
334 data[0] = 25;
335 data[1] = 80;
336 data[2] = 0;
337 data[3] = 0;
339 else
341 memset(data, 0, 8);
343 request->return_value = 0;
344 fsFinishRequest(request);
345 return 0;
347 request->return_value = -1;
348 fsFinishRequest(request);
349 break;
350 default:
351 fsFinishRequest(request);
353 return 0;
355 static int sysGfxRequest(struct FsDeviceFile *file, FsRequest *request)
357 switch (request->type)
359 case FS_REQUEST_READ:
360 fsFinishRequest(request);
361 break;
362 case FS_REQUEST_WRITE:
363 fsFinishRequest(request);
364 break;
365 case FS_REQUEST_IOCTL:
366 fsFinishRequest(request);
367 break;
368 default:
369 fsFinishRequest(request);
371 return 0;
374 int sysInitTerminals(void)
376 // Create text terminals
377 memset(textterms, 0, sizeof(SysTextTerminal) * 8);
378 int i;
379 for (i = 0; i < 8; i++)
381 textterms[i].file.path = termnames[i];
382 textterms[i].file.query_request = sysTerminalRequest;
383 textterms[i].inputbuffer_size = 256;
384 textterms[i].inputbuffer = malloc(256);
385 textterms[i].screendata = malloc(screenwidth * screenheight * 2);
386 memset(textterms[i].screendata, 0, screenwidth * screenheight * 2);
387 textterms[i].fgcolor = 0x7;
388 textterms[i].bgcolor = 0x0;
389 textterms[i].echo = 1;
390 fsCreateDeviceFile(&textterms[i].file);
392 // Create graphical terminals
393 memset(gfxterms, 0, sizeof(SysGfxTerminal) * 4);
394 for (i = 0; i < 4; i++)
396 gfxterms[i].file.path = termnames[i + 8];
397 gfxterms[i].file.query_request = sysGfxRequest;
398 fsCreateDeviceFile(&gfxterms[i].file);
400 // Clear screen
401 keTerminalInitialized();
402 memset(vidmem, 0, 80 * 25 * 2);
403 return 0;
406 void sysSetCurrentTerminal(int terminal)
408 keLockSpinlock(&terminallock);
409 if (terminal != currentterm)
411 if (terminal < 8)
413 memcpy(vidmem, textterms[terminal].screendata, screenwidth * screenheight * 2);
415 else
417 memset(vidmem, 0, screenwidth * screenheight * 2);
419 currentterm = terminal;
421 keUnlockSpinlock(&terminallock);
423 int sysGetCurrentTerminal(void)
425 return currentterm;
428 int sysTerminalInjectKey(int key, int modifiers, int down)
430 KeExecLevel oldlevel = keSetExecutionLevel(KE_LEVEL_HIGH);
431 keLockSpinlock(&terminallock);
432 if (currentterm < 8)
434 SysTextTerminal *terminal = &textterms[currentterm];
435 // SIGINT
436 if (control_pressed && (key == 'C'))
438 // TODO
440 if ((key < 256) && down)
442 if (terminal->echo)
444 // Draw char
445 sysTerminalWriteChar(terminal, key, 1);
447 // Add key to buffer
448 if (terminal->inputbuffer_pos < terminal->inputbuffer_size)
450 terminal->inputbuffer[terminal->inputbuffer_pos] = key;
451 terminal->inputbuffer_pos++;
453 while (terminal->requestcount && (terminal->inputbuffer_pos >= (int)terminal->requests[0]->bufferlength))
455 // Answer request
456 FsRequest *request = terminal->requests[0];
457 memcpy(request->buffer, terminal->inputbuffer, request->bufferlength);
458 memmove(terminal->inputbuffer, terminal->inputbuffer + request->bufferlength,
459 terminal->inputbuffer_pos - request->bufferlength);
460 terminal->inputbuffer_pos -= request->bufferlength;
461 request->return_value = request->bufferlength;
462 fsFinishRequest(request);
463 // Delete request from queue
464 memmove(terminal->requests, terminal->requests + 1, (terminal->requestcount - 1) * sizeof(FsRequest*));
465 terminal->requestcount--;
466 terminal->requests = realloc(terminal->requests, sizeof(FsRequest*) * terminal->requestcount);
469 else
471 if (key == SYS_KEY_LCONTROL)
473 control_pressed = down;
475 // Changing terminals
476 if (control_pressed)
478 if ((key >= SYS_KEY_F1) && (key <= SYS_KEY_F12))
480 keUnlockSpinlock(&terminallock);
481 sysSetCurrentTerminal(key - SYS_KEY_F1);
482 keLockSpinlock(&terminallock);
487 else
489 // TODO
491 keUnlockSpinlock(&terminallock);
492 keSetExecutionLevel(oldlevel);
493 return 0;
496 char *sysTerminalPreparePanic(int *width, int *height)
498 *width = 80;
499 *height = 25;
500 return (char*)0xC00B8000;