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"
25 #include "fs/request.h"
31 static char *termnames
[12] =
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
)
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);
74 static void sysTerminalWriteChar(SysTextTerminal
*terminal
, char c
, int screen
)
76 if (terminal
->x
>= 80)
80 if (terminal
->y
== 25)
81 sysTerminalScroll(terminal
, 1, screen
);
83 int position
= (screenwidth
* terminal
->y
+ terminal
->x
) * 2;
89 if (terminal
->y
== 25)
90 sysTerminalScroll(terminal
, 1, screen
);
96 sysTerminalWriteChar(terminal
, ' ', screen
);
97 while (terminal
->x
% 7)
98 sysTerminalWriteChar(terminal
, ' ', screen
);
101 terminal
->screendata
[position
] = c
;
102 terminal
->screendata
[position
+ 1] = (terminal
->brightfg
<< 3) + (terminal
->bgcolor
<< 4) + terminal
->fgcolor
;
105 vidmem
[position
] = c
;
106 vidmem
[position
+ 1] = (terminal
->brightfg
<< 3) + (terminal
->bgcolor
<< 4) + terminal
->fgcolor
;
113 static int sysTerminalWriteEscape(SysTextTerminal
*terminal
, char *data
, int size
, int screen
)
119 if (!size
) return written
;
127 if (!size
) return written
;
134 int parameters
[10] = {0};
135 while (isdigit(*data
))
137 parameters
[paramcount
] = *data
- '0';
141 if (!size
) return written
;
142 if (!size
) return written
;
144 while (isdigit(*data
))
146 parameters
[paramcount
] = parameters
[paramcount
] * 10 + *data
- '0';
150 if (!size
) return written
;
153 if (paramcount
== 10) return written
;
159 if (!size
) return written
;
168 if ((paramcount
>= 1) && (parameters
[0] == 2))
171 memset(terminal
->screendata
, 0, screenwidth
* screenheight
* 2);
174 memset(vidmem
, 0, screenwidth
* screenheight
* 2);
180 for (i
= 0; i
< 10; i
++)
182 if (i
== paramcount
) break;
183 switch (parameters
[i
])
186 terminal
->brightfg
= 1;
189 terminal
->brightfg
= 0;
192 terminal
->fgcolor
= 0;
195 terminal
->fgcolor
= 4;
198 terminal
->fgcolor
= 2;
201 terminal
->fgcolor
= 6;
204 terminal
->fgcolor
= 1;
207 terminal
->fgcolor
= 5;
210 terminal
->fgcolor
= 3;
213 terminal
->fgcolor
= 7;
216 terminal
->bgcolor
= 0;
219 terminal
->bgcolor
= 4;
222 terminal
->bgcolor
= 2;
225 terminal
->bgcolor
= 6;
228 terminal
->bgcolor
= 1;
231 terminal
->bgcolor
= 5;
234 terminal
->bgcolor
= 3;
237 terminal
->bgcolor
= 7;
243 // Set cursor position
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;
258 static void sysTerminalWrite(SysTextTerminal
*terminal
, char *data
, int size
, int screen
)
261 for (i
= 0; i
< size
; i
++)
265 i
+= sysTerminalWriteEscape(terminal
, data
+ i
, size
- i
, screen
);
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
);
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
);
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
);
320 case FS_REQUEST_IOCTLSIZE
:
321 if (request
->offset
== 0x10)
323 request
->return_value
= 8;
324 fsFinishRequest(request
);
328 case FS_REQUEST_IOCTL
:
329 if (request
->offset
== 0x10)
331 uint16_t *data
= request
->buffer
;
343 request
->return_value
= 0;
344 fsFinishRequest(request
);
347 request
->return_value
= -1;
348 fsFinishRequest(request
);
351 fsFinishRequest(request
);
355 static int sysGfxRequest(struct FsDeviceFile
*file
, FsRequest
*request
)
357 switch (request
->type
)
359 case FS_REQUEST_READ
:
360 fsFinishRequest(request
);
362 case FS_REQUEST_WRITE
:
363 fsFinishRequest(request
);
365 case FS_REQUEST_IOCTL
:
366 fsFinishRequest(request
);
369 fsFinishRequest(request
);
374 int sysInitTerminals(void)
376 // Create text terminals
377 memset(textterms
, 0, sizeof(SysTextTerminal
) * 8);
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
);
401 keTerminalInitialized();
402 memset(vidmem
, 0, 80 * 25 * 2);
406 void sysSetCurrentTerminal(int terminal
)
408 keLockSpinlock(&terminallock
);
409 if (terminal
!= currentterm
)
413 memcpy(vidmem
, textterms
[terminal
].screendata
, screenwidth
* screenheight
* 2);
417 memset(vidmem
, 0, screenwidth
* screenheight
* 2);
419 currentterm
= terminal
;
421 keUnlockSpinlock(&terminallock
);
423 int sysGetCurrentTerminal(void)
428 int sysTerminalInjectKey(int key
, int modifiers
, int down
)
430 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
431 keLockSpinlock(&terminallock
);
434 SysTextTerminal
*terminal
= &textterms
[currentterm
];
436 if (control_pressed
&& (key
== 'C'))
440 if ((key
< 256) && down
)
445 sysTerminalWriteChar(terminal
, key
, 1);
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
))
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
);
471 if (key
== SYS_KEY_LCONTROL
)
473 control_pressed
= down
;
475 // Changing terminals
478 if ((key
>= SYS_KEY_F1
) && (key
<= SYS_KEY_F12
))
480 keUnlockSpinlock(&terminallock
);
481 sysSetCurrentTerminal(key
- SYS_KEY_F1
);
482 keLockSpinlock(&terminallock
);
491 keUnlockSpinlock(&terminallock
);
492 keSetExecutionLevel(oldlevel
);
496 char *sysTerminalPreparePanic(int *width
, int *height
)
500 return (char*)0xC00B8000;