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_OPEN
:
284 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
285 keLockSpinlock(&terminallock
);
286 if (!terminal
->owner
&& !terminal
->opencount
)
288 terminal
->owner
= request
->process
;
290 if (terminal
->owner
== request
->process
)
292 terminal
->opencount
++;
294 keUnlockSpinlock(&terminallock
);
295 keSetExecutionLevel(oldlevel
);
296 fsFinishRequest(request
);
299 case FS_REQUEST_CLOSE
:
301 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
302 keLockSpinlock(&terminallock
);
303 if (terminal
->owner
== request
->process
)
305 terminal
->opencount
--;
306 if (!terminal
->opencount
) terminal
->owner
= 0;
308 keUnlockSpinlock(&terminallock
);
309 keSetExecutionLevel(oldlevel
);
310 fsFinishRequest(request
);
313 case FS_REQUEST_READ
:
315 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
316 keLockSpinlock(&terminallock
);
317 if (!terminal
->requestcount
&& (terminal
->inputbuffer_pos
>= (int)request
->bufferlength
))
319 // Directly copy from the buffer
320 memcpy(request
->buffer
, terminal
->inputbuffer
, request
->bufferlength
);
321 memmove(terminal
->inputbuffer
, terminal
->inputbuffer
+ request
->bufferlength
,
322 terminal
->inputbuffer_pos
- request
->bufferlength
);
323 terminal
->inputbuffer_pos
-= request
->bufferlength
;
324 request
->return_value
= request
->bufferlength
;
325 fsFinishRequest(request
);
329 // Put the request into the queue
330 terminal
->requests
= realloc(terminal
->requests
, sizeof(FsRequest
*) * (terminal
->requestcount
+ 1));
331 terminal
->requests
[terminal
->requestcount
] = request
;
332 terminal
->requestcount
++;
334 keUnlockSpinlock(&terminallock
);
335 keSetExecutionLevel(oldlevel
);
338 case FS_REQUEST_WRITE
:
340 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
341 keLockSpinlock(&terminallock
);
342 sysTerminalWrite(terminal
, request
->buffer
, request
->bufferlength
,
343 index
== currentterm
);
344 keUnlockSpinlock(&terminallock
);
345 keSetExecutionLevel(oldlevel
);
346 request
->return_value
= request
->bufferlength
;
347 fsFinishRequest(request
);
350 case FS_REQUEST_IOCTLSIZE
:
351 if (request
->offset
== 0x10)
353 request
->return_value
= 8;
354 fsFinishRequest(request
);
358 case FS_REQUEST_IOCTL
:
359 if (request
->offset
== 0x10)
361 uint16_t *data
= request
->buffer
;
373 request
->return_value
= 0;
374 fsFinishRequest(request
);
377 request
->return_value
= -1;
378 fsFinishRequest(request
);
381 fsFinishRequest(request
);
385 static int sysGfxRequest(struct FsDeviceFile
*file
, FsRequest
*request
)
387 switch (request
->type
)
389 case FS_REQUEST_READ
:
390 fsFinishRequest(request
);
392 case FS_REQUEST_WRITE
:
393 fsFinishRequest(request
);
395 case FS_REQUEST_IOCTL
:
396 fsFinishRequest(request
);
399 fsFinishRequest(request
);
404 int sysInitTerminals(void)
406 // Create text terminals
407 memset(textterms
, 0, sizeof(SysTextTerminal
) * 8);
409 for (i
= 0; i
< 8; i
++)
411 textterms
[i
].file
.path
= termnames
[i
];
412 textterms
[i
].file
.query_request
= sysTerminalRequest
;
413 textterms
[i
].inputbuffer_size
= 256;
414 textterms
[i
].inputbuffer
= malloc(256);
415 textterms
[i
].screendata
= malloc(screenwidth
* screenheight
* 2);
416 memset(textterms
[i
].screendata
, 0, screenwidth
* screenheight
* 2);
417 textterms
[i
].fgcolor
= 0x7;
418 textterms
[i
].bgcolor
= 0x0;
419 textterms
[i
].echo
= 1;
420 fsCreateDeviceFile(&textterms
[i
].file
);
422 // Create graphical terminals
423 memset(gfxterms
, 0, sizeof(SysGfxTerminal
) * 4);
424 for (i
= 0; i
< 4; i
++)
426 gfxterms
[i
].file
.path
= termnames
[i
+ 8];
427 gfxterms
[i
].file
.query_request
= sysGfxRequest
;
428 fsCreateDeviceFile(&gfxterms
[i
].file
);
431 keTerminalInitialized();
432 memset(vidmem
, 0, 80 * 25 * 2);
436 void sysSetCurrentTerminal(int terminal
)
438 keLockSpinlock(&terminallock
);
439 if (terminal
!= currentterm
)
443 memcpy(vidmem
, textterms
[terminal
].screendata
, screenwidth
* screenheight
* 2);
447 memset(vidmem
, 0, screenwidth
* screenheight
* 2);
449 currentterm
= terminal
;
451 keUnlockSpinlock(&terminallock
);
453 int sysGetCurrentTerminal(void)
458 int sysTerminalInjectKey(int key
, int modifiers
, int down
)
460 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
461 keLockSpinlock(&terminallock
);
464 SysTextTerminal
*terminal
= &textterms
[currentterm
];
466 if (control_pressed
&& (key
== 'c') && down
)
470 keSendSignal(terminal
->owner
, 0, SIGINT
);
471 keUnlockSpinlock(&terminallock
);
472 keSetExecutionLevel(oldlevel
);
476 if ((key
< 256) && down
)
481 sysTerminalWriteChar(terminal
, key
, 1);
484 if (terminal
->inputbuffer_pos
< terminal
->inputbuffer_size
)
486 terminal
->inputbuffer
[terminal
->inputbuffer_pos
] = key
;
487 terminal
->inputbuffer_pos
++;
489 while (terminal
->requestcount
&& (terminal
->inputbuffer_pos
>= (int)terminal
->requests
[0]->bufferlength
))
492 FsRequest
*request
= terminal
->requests
[0];
493 memcpy(request
->buffer
, terminal
->inputbuffer
, request
->bufferlength
);
494 memmove(terminal
->inputbuffer
, terminal
->inputbuffer
+ request
->bufferlength
,
495 terminal
->inputbuffer_pos
- request
->bufferlength
);
496 terminal
->inputbuffer_pos
-= request
->bufferlength
;
497 request
->return_value
= request
->bufferlength
;
498 fsFinishRequest(request
);
499 // Delete request from queue
500 memmove(terminal
->requests
, terminal
->requests
+ 1, (terminal
->requestcount
- 1) * sizeof(FsRequest
*));
501 terminal
->requestcount
--;
502 terminal
->requests
= realloc(terminal
->requests
, sizeof(FsRequest
*) * terminal
->requestcount
);
507 if (key
== SYS_KEY_LCONTROL
)
509 control_pressed
= down
;
511 // Changing terminals
514 if ((key
>= SYS_KEY_F1
) && (key
<= SYS_KEY_F12
))
516 keUnlockSpinlock(&terminallock
);
517 sysSetCurrentTerminal(key
- SYS_KEY_F1
);
518 keLockSpinlock(&terminallock
);
527 keUnlockSpinlock(&terminallock
);
528 keSetExecutionLevel(oldlevel
);
532 char *sysTerminalPreparePanic(int *width
, int *height
)
536 return (char*)0xC00B8000;