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"
30 static char *termnames
[12] =
45 static SysTextTerminal textterms
[8];
46 static SysGfxTerminal gfxterms
[4];
48 static int currentterm
= 0;
50 static int screenwidth
= 80;
51 static int screenheight
= 25;
53 static char *vidmem
= (char*)0xC00B8000;
55 static KeSpinlock terminallock
;
57 void keTerminalInitialized(void);
59 static void sysTerminalScroll(SysTextTerminal
*terminal
, int lines
, int screen
)
61 memmove(vidmem
, vidmem
+ lines
* 160, (25 - lines
) * 160);
62 memset(vidmem
+ (25 - lines
) * 160, 0, lines
* 160);
63 memmove(terminal
->screendata
, terminal
->screendata
+ lines
* 160, (25 - lines
) * 160);
64 memset(terminal
->screendata
+ (25 - lines
) * 160, 0, lines
* 160);
68 static void sysTerminalWriteChar(SysTextTerminal
*terminal
, char c
, int screen
)
70 int position
= (screenwidth
* terminal
->y
+ terminal
->x
) * 2;
76 if (terminal
->y
== 25)
77 sysTerminalScroll(terminal
, 1, screen
);
83 sysTerminalWriteChar(terminal
, ' ', screen
);
84 while (terminal
->x
% 7)
85 sysTerminalWriteChar(terminal
, ' ', screen
);
88 terminal
->screendata
[position
] = c
;
89 terminal
->screendata
[position
+ 1] = (terminal
->bgcolor
<< 4) + terminal
->fgcolor
;
93 vidmem
[position
+ 1] = (terminal
->bgcolor
<< 4) + terminal
->fgcolor
;
96 if (terminal
->x
== 80)
100 if (terminal
->y
== 25)
101 sysTerminalScroll(terminal
, 1, screen
);
108 static void sysTerminalWrite(SysTextTerminal
*terminal
, char *data
, int size
, int screen
)
111 for (i
= 0; i
< size
; i
++)
113 sysTerminalWriteChar(terminal
, data
[i
], screen
);
117 static int sysTerminalRequest(struct FsDeviceFile
*file
, FsRequest
*request
)
119 SysTextTerminal
*terminal
= (SysTextTerminal
*)file
;
120 int index
= ((uintptr_t)terminal
- (uintptr_t)textterms
) / sizeof(SysTextTerminal
);
122 switch (request
->type
)
124 case FS_REQUEST_READ
:
126 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
127 keSetExecutionLevel(KE_LEVEL_HIGH
);
128 keLockSpinlock(&terminallock
);
129 if (!terminal
->requestcount
&& (terminal
->inputbuffer_pos
>= (int)request
->bufferlength
))
131 // Directly copy from the buffer
132 memcpy(request
->buffer
, terminal
->inputbuffer
, request
->bufferlength
);
133 memmove(terminal
->inputbuffer
, terminal
->inputbuffer
+ request
->bufferlength
,
134 terminal
->inputbuffer_pos
- request
->bufferlength
);
135 terminal
->inputbuffer_pos
-= request
->bufferlength
;
136 request
->return_value
= request
->bufferlength
;
137 fsFinishRequest(request
);
141 // Put the request into the queue
142 terminal
->requests
= realloc(terminal
->requests
, sizeof(FsRequest
*) * (terminal
->requestcount
+ 1));
143 terminal
->requests
[terminal
->requestcount
] = request
;
144 terminal
->requestcount
++;
146 keUnlockSpinlock(&terminallock
);
147 keSetExecutionLevel(KE_LEVEL_NORMAL
);
150 case FS_REQUEST_WRITE
:
152 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
153 keLockSpinlock(&terminallock
);
154 sysTerminalWrite(terminal
, request
->buffer
, request
->bufferlength
,
155 index
== currentterm
);
156 keUnlockSpinlock(&terminallock
);
157 keSetExecutionLevel(oldlevel
);
158 request
->return_value
= request
->bufferlength
;
159 fsFinishRequest(request
);
162 case FS_REQUEST_IOCTL
:
163 request
->return_value
= -1;
164 fsFinishRequest(request
);
167 fsFinishRequest(request
);
171 static int sysGfxRequest(struct FsDeviceFile
*file
, FsRequest
*request
)
173 switch (request
->type
)
175 case FS_REQUEST_READ
:
176 fsFinishRequest(request
);
178 case FS_REQUEST_WRITE
:
179 fsFinishRequest(request
);
181 case FS_REQUEST_IOCTL
:
182 fsFinishRequest(request
);
185 fsFinishRequest(request
);
190 int sysInitTerminals(void)
192 // Create text terminals
193 memset(textterms
, 0, sizeof(SysTextTerminal
) * 8);
195 for (i
= 0; i
< 8; i
++)
197 textterms
[i
].file
.path
= termnames
[i
];
198 textterms
[i
].file
.query_request
= sysTerminalRequest
;
199 textterms
[i
].inputbuffer_size
= 256;
200 textterms
[i
].inputbuffer
= malloc(256);
201 textterms
[i
].screendata
= malloc(screenwidth
* screenheight
* 2);
202 memset(textterms
[i
].screendata
, 0, screenwidth
* screenheight
* 2);
203 textterms
[i
].fgcolor
= 0x7;
204 textterms
[i
].bgcolor
= 0x0;
205 textterms
[i
].echo
= 1;
206 fsCreateDeviceFile(&textterms
[i
].file
);
208 // Create graphical terminals
209 memset(gfxterms
, 0, sizeof(SysGfxTerminal
) * 4);
210 for (i
= 0; i
< 4; i
++)
212 gfxterms
[i
].file
.path
= termnames
[i
+ 8];
213 gfxterms
[i
].file
.query_request
= sysGfxRequest
;
214 fsCreateDeviceFile(&gfxterms
[i
].file
);
217 keTerminalInitialized();
218 memset(vidmem
, 0, 80 * 25 * 2);
222 void sysSetCurrentTerminal(int terminal
)
225 int sysGetCurrentTerminal(void)
230 int sysTerminalInjectKey(int key
, int modifiers
, int down
)
232 KeExecLevel oldlevel
= keSetExecutionLevel(KE_LEVEL_HIGH
);
233 keLockSpinlock(&terminallock
);
236 SysTextTerminal
*terminal
= &textterms
[currentterm
];
237 if ((key
< 256) && down
)
242 sysTerminalWriteChar(terminal
, key
, 1);
245 if (terminal
->inputbuffer_pos
< terminal
->inputbuffer_size
)
247 terminal
->inputbuffer
[terminal
->inputbuffer_pos
] = key
;
248 terminal
->inputbuffer_pos
++;
250 while (terminal
->requestcount
&& (terminal
->inputbuffer_pos
>= (int)terminal
->requests
[0]->bufferlength
))
253 FsRequest
*request
= terminal
->requests
[0];
254 memcpy(request
->buffer
, terminal
->inputbuffer
, request
->bufferlength
);
255 memmove(terminal
->inputbuffer
, terminal
->inputbuffer
+ request
->bufferlength
,
256 terminal
->inputbuffer_pos
- request
->bufferlength
);
257 terminal
->inputbuffer_pos
-= request
->bufferlength
;
258 request
->return_value
= request
->bufferlength
;
259 fsFinishRequest(request
);
260 // Delete request from queue
261 memmove(terminal
->requests
, terminal
->requests
+ 1, (terminal
->requestcount
- 1) * sizeof(FsRequest
*));
262 terminal
->requestcount
--;
263 terminal
->requests
= realloc(terminal
->requests
, sizeof(FsRequest
*) * terminal
->requestcount
);
271 keUnlockSpinlock(&terminallock
);
272 keSetExecutionLevel(oldlevel
);
276 char *sysTerminalPreparePanic(int *width
, int *height
)
280 return (char*)0xC00B8000;