Patch by Anton Yarotsky:
[reactos.git] / reactos / ntoskrnl / ex / hdlsterm.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ex/hdlsterm.c
5 * PURPOSE: Headless Terminal Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #include <debug.h>
13
14 /* GLOBALS *******************************************************************/
15
16 PHEADLESS_GLOBALS HeadlessGlobals;
17
18 /* FUNCTIONS *****************************************************************/
19
20 VOID
21 NTAPI
22 HdlspSendStringAtBaud(
23 IN PUCHAR String
24 )
25 {
26 /* Send every byte */
27 while (*String++ != ANSI_NULL)
28 {
29 InbvPortPutByte(HeadlessGlobals->TerminalPort, *String);
30 }
31 }
32
33 NTSTATUS
34 NTAPI
35 HdlspEnableTerminal(
36 IN BOOLEAN Enable
37 )
38 {
39 /* Enable if requested, as long as this isn't a PCI serial port crashing */
40 if ((Enable) &&
41 !(HeadlessGlobals->TerminalEnabled) &&
42 !((HeadlessGlobals->IsMMIODevice) && (HeadlessGlobals->InBugCheck)))
43 {
44 /* Initialize the COM port with cportlib */
45 HeadlessGlobals->TerminalEnabled = InbvPortInitialize(
46 HeadlessGlobals->TerminalBaudRate,
47 HeadlessGlobals->TerminalPortNumber,
48 HeadlessGlobals->TerminalPortAddress,
49 &HeadlessGlobals->TerminalPort,
50 HeadlessGlobals->IsMMIODevice);
51 if (!HeadlessGlobals->TerminalEnabled) return STATUS_UNSUCCESSFUL;
52
53 /* Cleanup the screen and reset the cursor */
54 HdlspSendStringAtBaud((PUCHAR)"\x1B[2J");
55 HdlspSendStringAtBaud((PUCHAR)"\x1B[H");
56
57 /* Enable FIFO */
58 InbvPortEnableFifo(HeadlessGlobals->TerminalPort, TRUE);
59 }
60 else if (!Enable)
61 {
62 /* Specific case when headless is being disabled */
63 InbvPortTerminate(HeadlessGlobals->TerminalPort);
64 HeadlessGlobals->TerminalPort = 0;
65 HeadlessGlobals->TerminalEnabled = FALSE;
66 }
67 return STATUS_SUCCESS;
68 }
69
70 VOID
71 NTAPI
72 HeadlessInit(
73 IN PLOADER_PARAMETER_BLOCK LoaderBlock
74 )
75 {
76 PHEADLESS_LOADER_BLOCK HeadlessBlock;
77
78 HeadlessBlock = LoaderBlock->Extension->HeadlessLoaderBlock;
79 if (!HeadlessBlock) return;
80 if ((HeadlessBlock->PortNumber > 4) && (HeadlessBlock->UsedBiosSettings)) return;
81
82 HeadlessGlobals = ExAllocatePoolWithTag(
83 NonPagedPool,
84 sizeof(HEADLESS_GLOBALS),
85 'sldH');
86 if (!HeadlessGlobals) return;
87
88 /* Zero and copy loader data */
89 RtlZeroMemory(HeadlessGlobals, sizeof(HEADLESS_GLOBALS));
90 HeadlessGlobals->TerminalPortNumber = HeadlessBlock->PortNumber;
91 HeadlessGlobals->TerminalPortAddress = HeadlessBlock->PortAddress;
92 HeadlessGlobals->TerminalBaudRate = HeadlessBlock->BaudRate;
93 HeadlessGlobals->TerminalParity = HeadlessBlock->Parity;
94 HeadlessGlobals->TerminalStopBits = HeadlessBlock->StopBits;
95 HeadlessGlobals->UsedBiosSettings = HeadlessBlock->UsedBiosSettings;
96 HeadlessGlobals->IsMMIODevice = HeadlessBlock->IsMMIODevice;
97 HeadlessGlobals->TerminalType = HeadlessBlock->TerminalType;
98 HeadlessGlobals->SystemGUID = HeadlessBlock->SystemGUID;
99
100 /* These two are opposites of each other */
101 if (HeadlessGlobals->IsMMIODevice) HeadlessGlobals->IsNonLegacyDevice = TRUE;
102
103 /* Check for a PCI device, warn that this isn't supported */
104 if (HeadlessBlock->PciDeviceId != PCI_INVALID_VENDORID)
105 {
106 DPRINT1("PCI Serial Ports not supported\n");
107 }
108
109 /* Log entries are not yet supported */
110 DPRINT1("FIXME: No Headless logging support\n");
111
112 /* Allocate temporary buffer */
113 HeadlessGlobals->TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, 80, 'sldH');
114 if (!HeadlessGlobals->TmpBuffer) return;
115
116 /* Windows seems to apply some special hacks for 9600 bps */
117 if (HeadlessGlobals->TerminalBaudRate == 9600)
118 {
119 DPRINT1("Please use other baud rate than 9600bps for now\n");
120 }
121
122 /* Enable the terminal */
123 HdlspEnableTerminal(TRUE);
124 }
125
126 VOID
127 NTAPI
128 HdlspPutString(
129 IN PUCHAR String
130 )
131 {
132 PUCHAR Dest = HeadlessGlobals->TmpBuffer;
133 UCHAR Char = 0;
134
135 /* Scan each character */
136 while (*String != ANSI_NULL)
137 {
138 /* Check for rotate, send existing buffer and restart from where we are */
139 if (Dest >= &HeadlessGlobals->TmpBuffer[79])
140 {
141 HeadlessGlobals->TmpBuffer[79] = ANSI_NULL;
142 HdlspSendStringAtBaud(HeadlessGlobals->TmpBuffer);
143 Dest = HeadlessGlobals->TmpBuffer;
144 }
145 else
146 {
147 /* Get the current character and check for special graphical chars */
148 Char = *String;
149 if (Char & 0x80)
150 {
151 switch (Char)
152 {
153 case 0xB0: case 0xB3: case 0xBA:
154 Char = '|';
155 break;
156 case 0xB1: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
157 Char = '%';
158 break;
159 case 0xB2: case 0xDB:
160 Char = '#';
161 break;
162 case 0xA9: case 0xAA: case 0xBB: case 0xBC: case 0xBF:
163 case 0xC0: case 0xC8: case 0xC9: case 0xD9: case 0xDA:
164 Char = '+';
165 break;
166 case 0xC4:
167 Char = '-';
168 break;
169 case 0xCD:
170 Char = '=';
171 break;
172 }
173 }
174
175 /* Anything else must be Unicode */
176 if (Char & 0x80)
177 {
178 /* Can't do Unicode yet */
179 UNIMPLEMENTED;
180 }
181 else
182 {
183 /* Add the modified char to the temporary buffer */
184 *Dest++ = Char;
185 }
186
187 /* Check the next char */
188 String++;
189 }
190 }
191
192 /* Finish and send */
193 *Dest = ANSI_NULL;
194 HdlspSendStringAtBaud(HeadlessGlobals->TmpBuffer);
195 }
196
197 NTSTATUS
198 NTAPI
199 HdlspDispatch(
200 IN HEADLESS_CMD Command,
201 IN PVOID InputBuffer,
202 IN SIZE_T InputBufferSize,
203 OUT PVOID OutputBuffer,
204 OUT PSIZE_T OutputBufferSize
205 )
206 {
207 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
208 ASSERT(HeadlessGlobals != NULL);
209 // ASSERT(HeadlessGlobals->PageLockHandle != NULL);
210
211 /* FIXME: This should be using the headless spinlock */
212
213 /* Ignore non-reentrant commands */
214 if ((Command != HeadlessCmdAddLogEntry) &&
215 (Command != HeadlessCmdStartBugCheck) &&
216 (Command != HeadlessCmdSendBlueScreenData) &&
217 (Command != HeadlessCmdDoBugCheckProcessing))
218 {
219 if (HeadlessGlobals->ProcessingCmd) return STATUS_UNSUCCESSFUL;
220
221 /* Don't allow these commands next time */
222 HeadlessGlobals->ProcessingCmd = TRUE;
223 }
224
225 /* Handle each command */
226 switch (Command)
227 {
228 case HeadlessCmdEnableTerminal:
229 break;
230 case HeadlessCmdCheckForReboot:
231 break;
232
233 case HeadlessCmdPutString:
234
235 /* Validate the existence of an input buffer */
236 if (!InputBuffer)
237 {
238 Status = STATUS_INVALID_PARAMETER;
239 goto Reset;
240 }
241
242 /* Terminal should be on */
243 if (HeadlessGlobals->TerminalEnabled)
244 {
245 /* Print each byte in the string making sure VT100 chars are used */
246 PHEADLESS_CMD_PUT_STRING PutString = (PVOID)InputBuffer;
247 HdlspPutString(PutString->String);
248 }
249
250 /* Return success either way */
251 Status = STATUS_SUCCESS;
252 break;
253 case HeadlessCmdClearDisplay:
254 break;
255 case HeadlessCmdClearToEndOfDisplay:
256 break;
257 case HeadlessCmdClearToEndOfLine:
258 break;
259 case HeadlessCmdDisplayAttributesOff:
260 break;
261 case HeadlessCmdDisplayInverseVideo:
262 break;
263 case HeadlessCmdSetColor:
264 break;
265 case HeadlessCmdPositionCursor:
266 break;
267 case HeadlessCmdTerminalPoll:
268 break;
269 case HeadlessCmdGetByte:
270 break;
271 case HeadlessCmdGetLine:
272 break;
273 case HeadlessCmdStartBugCheck:
274 break;
275 case HeadlessCmdDoBugCheckProcessing:
276 break;
277 case HeadlessCmdQueryInformation:
278 break;
279 case HeadlessCmdAddLogEntry:
280 break;
281 case HeadlessCmdDisplayLog:
282 break;
283 case HeadlessCmdSetBlueScreenData:
284 break;
285 case HeadlessCmdSendBlueScreenData:
286 break;
287 case HeadlessCmdQueryGUID:
288 break;
289 case HeadlessCmdPutData:
290 break;
291 default:
292 break;
293 }
294
295 Reset:
296 /* Unset prcessing state */
297 if ((Command != HeadlessCmdAddLogEntry) &&
298 (Command != HeadlessCmdStartBugCheck) &&
299 (Command != HeadlessCmdSendBlueScreenData) &&
300 (Command != HeadlessCmdDoBugCheckProcessing))
301 {
302 ASSERT(HeadlessGlobals->ProcessingCmd == TRUE);
303 HeadlessGlobals->ProcessingCmd = FALSE;
304 }
305
306 //UNIMPLEMENTED;
307 return STATUS_SUCCESS;
308 }
309
310 /*
311 * @unimplemented
312 */
313 NTSTATUS
314 NTAPI
315 HeadlessDispatch(
316 IN HEADLESS_CMD Command,
317 IN PVOID InputBuffer,
318 IN SIZE_T InputBufferSize,
319 OUT PVOID OutputBuffer,
320 OUT PSIZE_T OutputBufferSize
321 )
322 {
323 /* Check for stubs that will expect something even with headless off */
324 if (!HeadlessGlobals)
325 {
326 /* Don't allow the SAC to connect */
327 if (Command == HeadlessCmdEnableTerminal) return STATUS_UNSUCCESSFUL;
328
329 /* Send bogus reply */
330 if ((Command == HeadlessCmdQueryInformation) ||
331 (Command == HeadlessCmdGetByte) ||
332 (Command == HeadlessCmdGetLine) ||
333 (Command == HeadlessCmdCheckForReboot) ||
334 (Command == HeadlessCmdTerminalPoll))
335 {
336 if (!(OutputBuffer) || !(OutputBufferSize)) return STATUS_INVALID_PARAMETER;
337 RtlZeroMemory(OutputBuffer, *OutputBufferSize);
338 }
339 return STATUS_SUCCESS;
340 }
341
342 /* Do the real work */
343 return HdlspDispatch(
344 Command,
345 InputBuffer,
346 InputBufferSize,
347 OutputBuffer,
348 OutputBufferSize);
349 }
350
351 /* EOF */