]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/Devices/Console/daConsole.c
Fixed header comment
[mirror_edk2.git] / StdLib / LibC / Uefi / Devices / Console / daConsole.c
CommitLineData
53e1e5c6 1/** @file\r
2 Abstract device driver for the UEFI Console.\r
3\r
4 Manipulates abstractions for stdin, stdout, stderr.\r
5\r
6 Copyright (c) 2010 - 2011, 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/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Protocol/SimpleTextIn.h>\r
21#include <Protocol/SimpleTextOut.h>\r
22\r
23#include <LibConfig.h>\r
53e1e5c6 24\r
25#include <errno.h>\r
26#include <wctype.h>\r
27#include <wchar.h>\r
76beedc0 28#include <stdarg.h>\r
53e1e5c6 29#include <sys/fcntl.h>\r
0c1992fb 30#include <unistd.h>\r
53e1e5c6 31#include <kfile.h>\r
32#include <Device/Device.h>\r
33#include <MainData.h>\r
34\r
35static const CHAR16* const\r
36stdioNames[NUM_SPECIAL] = {\r
37 L"stdin:", L"stdout:", L"stderr:"\r
38};\r
39\r
40static const int stdioFlags[NUM_SPECIAL] = {\r
41 O_RDONLY, // stdin\r
42 O_WRONLY, // stdout\r
43 O_WRONLY // stderr\r
44};\r
45\r
46static DeviceNode *ConNode[NUM_SPECIAL];\r
47static ConInstance *ConInstanceList;\r
48\r
d7ce7006 49static wchar_t *ConReadBuf;\r
50\r
51/* Flags settable by Ioctl */\r
52static BOOLEAN TtyCooked;\r
53static BOOLEAN TtyEcho;\r
54\r
53e1e5c6 55ssize_t\r
56WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)\r
57{\r
58 UINTN i;\r
59 wint_t wc;\r
60\r
61 for(i = 0; i < n; ++i) {\r
62 wc = btowc(*buf++);\r
63 if( wc == 0) {\r
64 break;\r
65 };\r
66 if(wc < 0) {\r
67 wc = BLOCKELEMENT_LIGHT_SHADE;\r
68 }\r
69 if(wc == L'\n') {\r
70 *dest++ = L'\r';\r
71 }\r
72 *dest++ = (CHAR16)wc;\r
73 }\r
74 *dest = 0;\r
75 return (ssize_t)i;\r
76}\r
77\r
78static\r
79int\r
80EFIAPI\r
81da_ConClose(\r
82 IN struct __filedes *filp\r
83)\r
84{\r
85 ConInstance *Stream;\r
86\r
87 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
88 // Quick check to see if Stream looks reasonable\r
89 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
90 EFIerrno = RETURN_INVALID_PARAMETER;\r
91 return -1; // Looks like a bad File Descriptor pointer\r
92 }\r
93 gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed\r
94 return RETURN_SUCCESS;\r
95}\r
96\r
97static\r
98off_t\r
99EFIAPI\r
100da_ConSeek(\r
101 struct __filedes *filp,\r
102 off_t Position,\r
103 int whence ///< Ignored by Console\r
104)\r
105{\r
106 ConInstance *Stream;\r
107 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
108 XYoffset CursorPos;\r
109\r
110 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
111 // Quick check to see if Stream looks reasonable\r
112 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
113 EFIerrno = RETURN_INVALID_PARAMETER;\r
114 return -1; // Looks like a bad This pointer\r
115 }\r
116 if(Stream->InstanceNum == STDIN_FILENO) {\r
117 // Seek is not valid for stdin\r
118 EFIerrno = RETURN_UNSUPPORTED;\r
119 return -1;\r
120 }\r
121 // Everything is OK to do the final verification and "seek".\r
122 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
123 CursorPos.Offset = Position;\r
124\r
125 EFIerrno = Proto->SetCursorPosition(Proto,\r
126 (INTN)CursorPos.XYpos.Column,\r
127 (INTN)CursorPos.XYpos.Row);\r
128\r
129 if(RETURN_ERROR(EFIerrno)) {\r
130 return -1;\r
131 }\r
132 else {\r
133 return Position;\r
134 }\r
135}\r
136\r
53e1e5c6 137/* Write a NULL terminated WCS to the EFI console.\r
138\r
139 @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if\r
140 the string couldn't be displayed.\r
141 @param[in] Buffer The WCS string to be displayed\r
142\r
143 @return The number of characters written.\r
144*/\r
145static\r
146ssize_t\r
147EFIAPI\r
148da_ConWrite(\r
149 IN struct __filedes *filp,\r
150 IN off_t *Position,\r
151 IN size_t BufferSize,\r
152 IN const void *Buffer\r
153 )\r
154{\r
155 EFI_STATUS Status;\r
156 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
157 ConInstance *Stream;\r
158 ssize_t NumChar;\r
159 //XYoffset CursorPos;\r
160\r
161 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
162 // Quick check to see if Stream looks reasonable\r
163 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
164 EFIerrno = RETURN_INVALID_PARAMETER;\r
165 return -1; // Looks like a bad This pointer\r
166 }\r
167 if(Stream->InstanceNum == STDIN_FILENO) {\r
168 // Write is not valid for stdin\r
169 EFIerrno = RETURN_UNSUPPORTED;\r
170 return -1;\r
171 }\r
172 // Everything is OK to do the write.\r
173 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
174\r
175 // Convert string from MBCS to WCS and translate \n to \r\n.\r
176 NumChar = WideTtyCvt(gMD->UString, (const char *)Buffer, BufferSize);\r
177 //if(NumChar > 0) {\r
178 // BufferSize = (size_t)(NumChar * sizeof(CHAR16));\r
179 //}\r
180 BufferSize = NumChar;\r
181\r
182 //if( Position != NULL) {\r
183 // CursorPos.Offset = (UINT64)*Position;\r
184\r
185 // Status = Proto->SetCursorPosition(Proto,\r
186 // (INTN)CursorPos.XYpos.Column,\r
187 // (INTN)CursorPos.XYpos.Row);\r
188 // if(RETURN_ERROR(Status)) {\r
189 // return -1;\r
190 // }\r
191 //}\r
192\r
193 // Send the Unicode buffer to the console\r
194 Status = Proto->OutputString( Proto, gMD->UString);\r
195 // Depending on status, update BufferSize and return\r
196 if(RETURN_ERROR(Status)) {\r
197 BufferSize = 0; // We don't really know how many characters made it out\r
198 }\r
199 else {\r
200 //BufferSize = NumChar;\r
201 Stream->NumWritten += NumChar;\r
202 }\r
203 EFIerrno = Status;\r
204 return BufferSize;\r
205}\r
206\r
d7ce7006 207/** Read characters from the console input device.\r
208\r
209 @param[in,out] filp Pointer to file descriptor for this file.\r
210 @param[in,out] offset Ignored.\r
211 @param[in] BufferSize Buffer size, in bytes.\r
212 @param[out] Buffer Buffer in which to place the read characters.\r
213\r
214 @return Number of bytes actually placed into Buffer.\r
215\r
216 @todo Handle encodings other than ASCII-7 and UEFI.\r
217**/\r
218static\r
219ssize_t\r
220EFIAPI\r
221da_ConRead(\r
222 IN OUT struct __filedes *filp,\r
223 IN OUT off_t *offset, // Console ignores this\r
224 IN size_t BufferSize,\r
225 OUT VOID *Buffer\r
226)\r
227{\r
228 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
229 ConInstance *Stream;\r
230 wchar_t *OutPtr;\r
231 EFI_INPUT_KEY Key;\r
232 UINTN NumChar;\r
233 UINTN Edex;\r
234 EFI_STATUS Status = RETURN_SUCCESS;\r
235 UINTN i;\r
236 char EchoBuff[MB_CUR_MAX + 1];\r
237 int NumEcho;\r
238\r
239 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
240 // Quick check to see if Stream looks reasonable\r
241 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
242 EFIerrno = RETURN_INVALID_PARAMETER;\r
243 return -1; // Looks like a bad This pointer\r
244 }\r
245 if(Stream->InstanceNum != STDIN_FILENO) {\r
246 // Read only valid for stdin\r
247 EFIerrno = RETURN_UNSUPPORTED;\r
248 return -1;\r
249 }\r
250 // It looks like things are OK for trying to read\r
251 // We will accumulate *BufferSize characters or until we encounter\r
252 // an "activation" character. Currently any control character.\r
253 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
254 OutPtr = ConReadBuf;\r
255 NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;\r
256 i = 0;\r
257 do {\r
258 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
259 Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
260 if(Status != RETURN_SUCCESS) {\r
261 break;\r
262 }\r
263 Status = Proto->ReadKeyStroke(Proto, &Key);\r
264 if(Status != RETURN_SUCCESS) {\r
265 break;\r
266 }\r
267 }\r
268 else {\r
269 Key.ScanCode = Stream->UnGetKey.ScanCode;\r
270 Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;\r
271 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
272 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
273 }\r
274 if(Key.ScanCode == SCAN_NULL) {\r
275 NumEcho = 0;\r
276 if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
277 *OutPtr++ = CHAR_LINEFEED;\r
278 NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);\r
279 }\r
280 else {\r
281 *OutPtr++ = Key.UnicodeChar;\r
282 NumEcho = wctomb(EchoBuff, Key.UnicodeChar);\r
283 }\r
284 ++i;\r
285 EchoBuff[NumEcho] = 0; /* Terminate the Echo buffer */\r
286 if(TtyEcho) {\r
287 /* Echo the character just input */\r
288 da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);\r
289 }\r
290 }\r
291 if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code\r
292 break;\r
293 }\r
294 } while(i < NumChar);\r
295\r
296 *OutPtr = L'\0'; // Terminate the input buffer\r
297\r
298 /* Convert the input buffer and place in Buffer.\r
299 If the fully converted input buffer won't fit, write what will and\r
300 leave the rest in ConReadBuf with ConReadLeft indicating how many\r
301 unconverted characters remain in ConReadBuf.\r
302 */\r
303 NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize); /* Re-use NumEcho to hold number of bytes in Buffer */\r
304 /* More work needs to be done before locales other than C can be supported. */\r
305\r
306 EFIerrno = Status;\r
307 return (ssize_t)NumEcho; // Will be 0 if we didn't get a key\r
308}\r
309\r
53e1e5c6 310/** Console-specific helper function for the fstat() function.\r
311\r
312 st_size Set to number of characters read for stdin and number written for stdout and stderr.\r
313 st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode.\r
314 st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr\r
315 st_blksize Set to 1 since this is a character device\r
316\r
317 All other members of the stat structure are left unchanged.\r
318**/\r
319static\r
320int\r
321EFIAPI\r
322da_ConStat(\r
323 struct __filedes *filp,\r
324 struct stat *Buffer,\r
325 void *Something\r
326 )\r
327{\r
328 ConInstance *Stream;\r
329 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
330 XYoffset CursorPos;\r
331 INT32 OutMode;\r
332 UINTN ModeCol;\r
333 UINTN ModeRow;\r
334\r
335// ConGetInfo\r
336 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
337 // Quick check to see if Stream looks reasonable\r
338 if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'\r
339 (Buffer == NULL))\r
340 {\r
341 EFIerrno = RETURN_INVALID_PARAMETER;\r
342 return -1;\r
343 }\r
344 // All of our parameters are correct, so fill in the information.\r
345 Buffer->st_blksize = 1;\r
346\r
347// ConGetPosition\r
348 if(Stream->InstanceNum == STDIN_FILENO) {\r
349 // This is stdin\r
350 Buffer->st_curpos = 0;\r
351 Buffer->st_size = (off_t)Stream->NumRead;\r
352 Buffer->st_physsize = 1;\r
353 }\r
354 else {\r
355 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
356 CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;\r
357 CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;\r
358 Buffer->st_curpos = (off_t)CursorPos.Offset;\r
359 Buffer->st_size = (off_t)Stream->NumWritten;\r
360\r
361 OutMode = Proto->Mode->Mode;\r
362 EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);\r
363 if(RETURN_ERROR(EFIerrno)) {\r
364 Buffer->st_physsize = 0;\r
365 }\r
366 else {\r
367 CursorPos.XYpos.Column = (UINT32)ModeCol;\r
368 CursorPos.XYpos.Row = (UINT32)ModeRow;\r
369 Buffer->st_physsize = (off_t)CursorPos.Offset;\r
370 }\r
371 }\r
372 return 0;\r
373}\r
374\r
375static\r
376int\r
377EFIAPI\r
378da_ConIoctl(\r
379 struct __filedes *filp,\r
380 ULONGN cmd,\r
76beedc0 381 va_list argp\r
53e1e5c6 382 )\r
383{\r
384 return -EPERM;\r
385}\r
386\r
387/** Open an abstract Console Device.\r
388**/\r
389int\r
390EFIAPI\r
391da_ConOpen(\r
d7ce7006 392 DeviceNode *DevNode,\r
53e1e5c6 393 struct __filedes *filp,\r
d7ce7006 394 int DevInstance, // Not used for console devices\r
53e1e5c6 395 wchar_t *Path, // Not used for console devices\r
d7ce7006 396 wchar_t *MPath // Not used for console devices\r
53e1e5c6 397 )\r
398{\r
399 ConInstance *Stream;\r
400\r
401 if((filp == NULL) ||\r
d7ce7006 402 (DevNode == NULL))\r
53e1e5c6 403 {\r
404 EFIerrno = RETURN_INVALID_PARAMETER;\r
8379337c 405 errno = EINVAL;\r
53e1e5c6 406 return -1;\r
407 }\r
d7ce7006 408 Stream = (ConInstance *)DevNode->InstanceList;\r
53e1e5c6 409 // Quick check to see if Stream looks reasonable\r
410 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
411 EFIerrno = RETURN_INVALID_PARAMETER;\r
8379337c 412 errno = EINVAL;\r
53e1e5c6 413 return -1; // Looks like a bad This pointer\r
414 }\r
d7ce7006 415 gMD->StdIo[Stream->InstanceNum] = Stream;\r
53e1e5c6 416 filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);\r
417 filp->f_offset = 0;\r
418 filp->f_ops = &Stream->Abstraction;\r
419\r
420 return 0;\r
421}\r
422\r
423#include <sys/poll.h>\r
424/* Returns a bit mask describing which operations could be completed immediately.\r
425\r
426 (POLLIN | POLLRDNORM) A Unicode character is available to read\r
427 (POLLIN) A ScanCode is ready.\r
428 (POLLOUT) The device is ready for output - always set on stdout and stderr.\r
429\r
430*/\r
431static\r
432short\r
433EFIAPI\r
434da_ConPoll(\r
435 struct __filedes *filp,\r
436 short events\r
437 )\r
438{\r
439 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
440 ConInstance *Stream;\r
441 EFI_STATUS Status = RETURN_SUCCESS;\r
442 short RdyMask = 0;\r
443\r
444 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
445 // Quick check to see if Stream looks reasonable\r
446 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
447 EFIerrno = RETURN_INVALID_PARAMETER;\r
448 return POLLNVAL; // Looks like a bad filp pointer\r
449 }\r
450 if(Stream->InstanceNum == 0) {\r
451 // Only input is supported for this device\r
452 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
453 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
454 Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey);\r
455 if(Status == RETURN_SUCCESS) {\r
456 RdyMask = POLLIN;\r
457 if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) {\r
458 RdyMask |= POLLRDNORM;\r
459 }\r
460 }\r
461 else {\r
462 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
463 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
464 }\r
465 }\r
466 }\r
467 else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2?\r
468 // Only output is supported for this device\r
469 RdyMask = POLLOUT;\r
470 }\r
471 else {\r
472 RdyMask = POLLERR; // Not one of the standard streams\r
473 }\r
474 EFIerrno = Status;\r
475\r
476 return (RdyMask & (events | POLL_RETONLY));\r
477}\r
478\r
479/** Construct the Console stream devices: stdin, stdout, stderr.\r
480\r
481 Allocate the instance structure and populate it with the information for\r
482 each stream device.\r
483**/\r
484RETURN_STATUS\r
485EFIAPI\r
486__Cons_construct(\r
487 IN EFI_HANDLE ImageHandle,\r
488 IN EFI_SYSTEM_TABLE *SystemTable\r
489)\r
490{\r
491 ConInstance *Stream;\r
492 RETURN_STATUS Status = RETURN_SUCCESS;\r
493 int i;\r
494\r
495 ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
d7ce7006 496 ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));\r
497 if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {\r
53e1e5c6 498 return RETURN_OUT_OF_RESOURCES;\r
499 }\r
500\r
501 for( i = 0; i < NUM_SPECIAL; ++i) {\r
502 // Get pointer to instance.\r
503 Stream = &ConInstanceList[i];\r
504\r
505 Stream->Cookie = CON_COOKIE;\r
506 Stream->InstanceNum = i;\r
507\r
508 switch(i) {\r
509 case STDIN_FILENO:\r
510 Stream->Dev = SystemTable->ConIn;\r
511 break;\r
512 case STDOUT_FILENO:\r
513 Stream->Dev = SystemTable->ConOut;\r
514 break;\r
515 case STDERR_FILENO:\r
516 if(SystemTable->StdErr == NULL) {\r
517 Stream->Dev = SystemTable->ConOut;\r
518 }\r
519 else {\r
520 Stream->Dev = SystemTable->StdErr;\r
521 }\r
522 break;\r
523 default:\r
524 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.\r
525 }\r
526\r
527 Stream->Abstraction.fo_close = &da_ConClose;\r
528 Stream->Abstraction.fo_read = &da_ConRead;\r
529 Stream->Abstraction.fo_write = &da_ConWrite;\r
530 Stream->Abstraction.fo_stat = &da_ConStat;\r
531 Stream->Abstraction.fo_lseek = &da_ConSeek;\r
532 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;\r
533 Stream->Abstraction.fo_ioctl = &da_ConIoctl;\r
534 Stream->Abstraction.fo_poll = &da_ConPoll;\r
535 Stream->Abstraction.fo_flush = &fnullop_flush;\r
536 Stream->Abstraction.fo_delete = &fbadop_delete;\r
537 Stream->Abstraction.fo_mkdir = &fbadop_mkdir;\r
538 Stream->Abstraction.fo_rmdir = &fbadop_rmdir;\r
539 Stream->Abstraction.fo_rename = &fbadop_rename;\r
540\r
541 Stream->NumRead = 0;\r
542 Stream->NumWritten = 0;\r
543 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
544 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
545\r
546 if(Stream->Dev == NULL) {\r
547 continue; // No device for this stream.\r
548 }\r
549 ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);\r
550 if(ConNode[i] == NULL) {\r
551 Status = EFIerrno;\r
552 break;\r
553 }\r
554 Stream->Parent = ConNode[i];\r
555 }\r
d7ce7006 556 /* Initialize Ioctl flags until Ioctl is really implemented. */\r
557 TtyCooked = TRUE;\r
558 TtyEcho = TRUE;\r
559\r
53e1e5c6 560 return Status;\r
561}\r
562\r
563RETURN_STATUS\r
564EFIAPI\r
565__Cons_deconstruct(\r
566 IN EFI_HANDLE ImageHandle,\r
567 IN EFI_SYSTEM_TABLE *SystemTable\r
568)\r
569{\r
570 int i;\r
571\r
572 for(i = 0; i < NUM_SPECIAL; ++i) {\r
573 if(ConNode[i] != NULL) {\r
574 FreePool(ConNode[i]);\r
575 }\r
576 }\r
577 if(ConInstanceList != NULL) {\r
578 FreePool(ConInstanceList);\r
579 }\r
d7ce7006 580 if(ConReadBuf != NULL) {\r
581 FreePool(ConReadBuf);\r
582 }\r
53e1e5c6 583\r
584 return RETURN_SUCCESS;\r
585}\r
586\r
587/* ######################################################################### */\r
588#if 0 /* Not implemented for Console */\r
589\r
590static\r
591int\r
592EFIAPI\r
593da_ConCntl(\r
594 struct __filedes *filp,\r
595 UINT32,\r
596 void *,\r
597 void *\r
598 )\r
599{\r
600}\r
601\r
602static\r
603int\r
604EFIAPI\r
605da_ConFlush(\r
606 struct __filedes *filp\r
607 )\r
608{\r
609 return 0;\r
610}\r
611#endif /* Not implemented for Console */\r