]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/Console.c
Standard Libraries for EDK II.
[mirror_edk2.git] / StdLib / LibC / Uefi / Console.c
CommitLineData
2aa62f2b 1/** @file\r
2 File abstractions of the console.\r
3\r
4 Manipulates EFI_FILE_PROTOCOL abstractions for stdin, stdout, stderr.\r
5\r
6 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
7 This program and the accompanying materials are licensed and made available under\r
8 the terms and conditions of the BSD License that accompanies this distribution.\r
9 The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16#include <Uefi.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21\r
22#include <LibConfig.h>\r
23#include <sys/EfiCdefs.h>\r
24\r
25#include <stdio.h>\r
26#include <sys/fcntl.h>\r
27#include <MainData.h>\r
28#include <Efi/Console.h>\r
29\r
30static const CHAR16 * stdioNames[NUM_SPECIAL] = {\r
31 L"stdin:", L"stdout:", L"stderr:"\r
32};\r
33static const int stdioFlags[NUM_SPECIAL] = {\r
34 O_RDONLY, // stdin\r
35 O_WRONLY, // stdout\r
36 O_WRONLY // stderr\r
37};\r
38\r
39static const int stdioMode[NUM_SPECIAL] = {\r
40 0444, // stdin\r
41 0222, // stdout\r
42 0222 // stderr\r
43};\r
44\r
45static\r
46EFI_STATUS\r
47EFIAPI\r
48ConClose(\r
49 IN EFI_FILE_PROTOCOL *This\r
50 )\r
51{\r
52 ConInstance *Stream;\r
53\r
54 Stream = BASE_CR(This, ConInstance, Abstraction);\r
55 // Quick check to see if Stream looks reasonable\r
56 if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'\r
57 return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer\r
58 }\r
59 // Nothing to Flush.\r
60 // Mark the Stream as closed.\r
61 Stream->Dev = NULL;\r
62\r
63 return RETURN_SUCCESS;\r
64}\r
65\r
66static\r
67EFI_STATUS\r
68EFIAPI\r
69ConDelete(\r
70 IN EFI_FILE_PROTOCOL *This\r
71 )\r
72{\r
73 return RETURN_UNSUPPORTED;\r
74}\r
75\r
76static\r
77EFI_STATUS\r
78EFIAPI\r
79ConRead(\r
80 IN EFI_FILE_PROTOCOL *This,\r
81 IN OUT UINTN *BufferSize,\r
82 OUT VOID *Buffer\r
83 )\r
84{\r
85 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
86 ConInstance *Stream;\r
87 CHAR16 *OutPtr;\r
88 EFI_INPUT_KEY Key;\r
89 UINTN NumChar;\r
90 UINTN Edex;\r
91 EFI_STATUS Status;\r
92 UINTN i;\r
93\r
94 Stream = BASE_CR(This, ConInstance, Abstraction);\r
95 // Quick check to see if Stream looks reasonable\r
96 if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'\r
97 return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer\r
98 }\r
99 if(Stream->Dev == NULL) {\r
100 // Can't read from an unopened Stream\r
101 return RETURN_DEVICE_ERROR;\r
102 }\r
103 if(Stream != &gMD->StdIo[0]) {\r
104 // Read only valid for stdin\r
105 return RETURN_UNSUPPORTED;\r
106 }\r
107 // It looks like things are OK for trying to read\r
108 // We will accumulate *BufferSize characters or until we encounter\r
109 // an "activation" character. Currently any control character.\r
110 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
111 OutPtr = Buffer;\r
112 NumChar = (*BufferSize - 1) / sizeof(CHAR16);\r
113 i = 0;\r
114 do {\r
115 Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
116 if(Status != EFI_SUCCESS) {\r
117 break;\r
118 }\r
119 Status = Proto->ReadKeyStroke(Proto, &Key);\r
120 if(Status != EFI_SUCCESS) {\r
121 break;\r
122 }\r
123 if(Key.ScanCode == SCAN_NULL) {\r
124 *OutPtr++ = Key.UnicodeChar;\r
125 ++i;\r
126 }\r
127 if(Key.UnicodeChar < 0x0020) { // If a control character, or a scan code\r
128 break;\r
129 }\r
130 } while(i < NumChar);\r
131 *BufferSize = i * sizeof(CHAR16);\r
132 return Status;\r
133}\r
134\r
135/* Write a NULL terminated WCS to the EFI console.\r
136\r
137 @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if\r
138 the string couldn't be displayed.\r
139 @parem[in] Buffer The WCS string to be displayed\r
140\r
141*/\r
142static\r
143EFI_STATUS\r
144EFIAPI\r
145ConWrite(\r
146 IN EFI_FILE_PROTOCOL *This,\r
147 IN OUT UINTN *BufferSize,\r
148 IN VOID *Buffer\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
153 ConInstance *Stream;\r
154 CHAR16 *MyBuf;\r
155 UINTN NumChar;\r
156\r
157 Stream = BASE_CR(This, ConInstance, Abstraction);\r
158 // Quick check to see if Stream looks reasonable\r
159 if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'\r
160 return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer\r
161 }\r
162 if(Stream->Dev == NULL) {\r
163 // Can't write to an unopened Stream\r
164 return RETURN_DEVICE_ERROR;\r
165 }\r
166 if(Stream == &gMD->StdIo[0]) {\r
167 // Write is not valid for stdin\r
168 return RETURN_UNSUPPORTED;\r
169 }\r
170 // Everything is OK to do the write.\r
171 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
172 MyBuf = (CHAR16 *)Buffer;\r
173 NumChar = *BufferSize;\r
174\r
175 // Send MyBuf to the console\r
176 Status = Proto->OutputString( Proto, MyBuf);\r
177 // Depending on status, update BufferSize and return\r
178 if(Status != EFI_SUCCESS) {\r
179 *BufferSize = 0; // We don't really know how many characters made it out\r
180 }\r
181 else {\r
182 *BufferSize = NumChar;\r
183 Stream->NumWritten += NumChar;\r
184 }\r
185 return Status;\r
186}\r
187\r
188static\r
189EFI_STATUS\r
190EFIAPI\r
191ConGetPosition(\r
192 IN EFI_FILE_PROTOCOL *This,\r
193 OUT UINT64 *Position\r
194 )\r
195{\r
196 ConInstance *Stream;\r
197 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
198 XYoffset CursorPos;\r
199\r
200 Stream = BASE_CR(This, ConInstance, Abstraction);\r
201 // Quick check to see if Stream looks reasonable\r
202 if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'\r
203 return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer\r
204 }\r
205 if(Stream == &gMD->StdIo[0]) {\r
206 // This is stdin\r
207 *Position = Stream->NumRead;\r
208 }\r
209 else {\r
210 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
211 CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;\r
212 CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;\r
213 *Position = CursorPos.Offset;\r
214 }\r
215 return RETURN_SUCCESS;\r
216}\r
217\r
218static\r
219EFI_STATUS\r
220EFIAPI\r
221ConSetPosition(\r
222 IN EFI_FILE_PROTOCOL *This,\r
223 IN UINT64 Position\r
224 )\r
225{\r
226 ConInstance *Stream;\r
227 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
228 XYoffset CursorPos;\r
229\r
230 Stream = BASE_CR(This, ConInstance, Abstraction);\r
231 // Quick check to see if Stream looks reasonable\r
232 if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'\r
233 return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer\r
234 }\r
235 if(Stream->Dev == NULL) {\r
236 // Can't write to an unopened Stream\r
237 return RETURN_DEVICE_ERROR;\r
238 }\r
239 if(Stream == &gMD->StdIo[0]) {\r
240 // Seek is not valid for stdin\r
241 return RETURN_UNSUPPORTED;\r
242 }\r
243 // Everything is OK to do the final verification and "seek".\r
244 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
245 CursorPos.Offset = Position;\r
246\r
247 return Proto->SetCursorPosition(Proto,\r
248 (INTN)CursorPos.XYpos.Column,\r
249 (INTN)CursorPos.XYpos.Row);\r
250}\r
251\r
252static\r
253EFI_STATUS\r
254EFIAPI\r
255ConGetInfo(\r
256 IN EFI_FILE_PROTOCOL *This,\r
257 IN EFI_GUID *InformationType,\r
258 IN OUT UINTN *BufferSize,\r
259 OUT VOID *Buffer\r
260 )\r
261{\r
262 EFI_FILE_INFO *InfoBuf;\r
263 ConInstance *Stream;\r
264\r
265 Stream = BASE_CR(This, ConInstance, Abstraction);\r
266 // Quick check to see if Stream looks reasonable\r
267 if((Stream->Cookie != 0x62416F49) || // Cookie == 'IoAb'\r
268 (Buffer == NULL))\r
269 {\r
270 return RETURN_INVALID_PARAMETER;\r
271 }\r
272 if(*BufferSize < sizeof(EFI_FILE_INFO)) {\r
273 *BufferSize = sizeof(EFI_FILE_INFO);\r
274 return RETURN_BUFFER_TOO_SMALL;\r
275 }\r
276 // All of our parameters are correct, so fill in the information.\r
277 (void) ZeroMem(Buffer, sizeof(EFI_FILE_INFO));\r
278 InfoBuf = (EFI_FILE_INFO *)Buffer;\r
279 InfoBuf->Size = sizeof(EFI_FILE_INFO);\r
280 InfoBuf->FileSize = 1;\r
281 InfoBuf->PhysicalSize = 1;\r
282 *BufferSize = sizeof(EFI_FILE_INFO);\r
283\r
284 return RETURN_SUCCESS;\r
285}\r
286\r
287static\r
288EFI_STATUS\r
289EFIAPI\r
290ConSetInfo(\r
291 IN EFI_FILE_PROTOCOL *This,\r
292 IN EFI_GUID *InformationType,\r
293 IN UINTN BufferSize,\r
294 IN VOID *Buffer\r
295 )\r
296{\r
297 return RETURN_UNSUPPORTED;\r
298}\r
299\r
300static\r
301EFI_STATUS\r
302EFIAPI\r
303ConFlush(\r
304 IN EFI_FILE_PROTOCOL *This\r
305 )\r
306{\r
307 return RETURN_SUCCESS;\r
308}\r
309\r
310EFI_STATUS\r
311EFIAPI\r
312ConOpen(\r
313 IN EFI_FILE_PROTOCOL *This,\r
314 OUT EFI_FILE_PROTOCOL **NewHandle,\r
315 IN CHAR16 *FileName,\r
316 IN UINT64 OpenMode, // Ignored\r
317 IN UINT64 Attributes // Ignored\r
318 )\r
319{\r
320 ConInstance *Stream;\r
321 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
322 UINTN Columns;\r
323 UINTN Rows;\r
324 int i;\r
325\r
326 if((NewHandle == NULL) ||\r
327 (FileName == NULL))\r
328 {\r
329 return RETURN_INVALID_PARAMETER;\r
330 }\r
331 // Process FileName\r
332 for(i = 0; i < NUM_SPECIAL; ++i) {\r
333 if(StrCmp( stdioNames[i], FileName) == 0) {\r
334 break;\r
335 }\r
336 }\r
337 if(i >= NUM_SPECIAL) {\r
338 return RETURN_NO_MAPPING;\r
339 }\r
340 // Get pointer to instance.\r
341 Stream = &gMD->StdIo[i];\r
342 if(Stream->Dev == NULL) {\r
343 // If this stream has been closed, then\r
344 // Initialize instance.\r
345 Stream->Cookie = 0x62416F49;\r
346 Stream->NumRead = 0;\r
347 Stream->NumWritten = 0;\r
348 switch(i) {\r
349 case 0:\r
350 Stream->Dev = gST->ConIn;\r
351 break;\r
352 case 1:\r
353 Stream->Dev = gST->ConOut;\r
354 break;\r
355 case 2:\r
356 if(gST->StdErr == NULL) {\r
357 Stream->Dev = gST->ConOut;\r
358 }\r
359 else {\r
360 Stream->Dev = gST->StdErr;\r
361 }\r
362 break;\r
363 default:\r
364 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.\r
365 }\r
366 Stream->Abstraction.Revision = 0x00010000;\r
367 Stream->Abstraction.Open = &ConOpen;\r
368 Stream->Abstraction.Close = &ConClose;\r
369 Stream->Abstraction.Delete = &ConDelete;\r
370 Stream->Abstraction.Read = &ConRead;\r
371 Stream->Abstraction.Write = &ConWrite;\r
372 Stream->Abstraction.GetPosition = &ConGetPosition;\r
373 Stream->Abstraction.SetPosition = &ConSetPosition;\r
374 Stream->Abstraction.GetInfo = &ConGetInfo;\r
375 Stream->Abstraction.SetInfo = &ConSetInfo;\r
376 Stream->Abstraction.Flush = &ConFlush;\r
377 // Get additional information if this is an Output stream\r
378 if(i != 0) {\r
379 Proto = Stream->Dev;\r
380 Stream->ConOutMode = Proto->Mode->Mode;\r
381 if( Proto->QueryMode(Proto, Stream->ConOutMode, &Columns, &Rows) != RETURN_SUCCESS) {\r
382 Stream->Dev = NULL; // Mark this stream as closed\r
383 return RETURN_INVALID_PARAMETER;\r
384 }\r
385 Stream->MaxConXY.XYpos.Column = (UINT32)Columns;\r
386 Stream->MaxConXY.XYpos.Row = (UINT32)Rows;\r
387 }\r
388 }\r
389 // Save NewHandle and return.\r
390 *NewHandle = &Stream->Abstraction;\r
391\r
392 return RETURN_SUCCESS;\r
393}\r