]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Uefi/Devices/Console/daConsole.c
927ec944eaeafa5d444322d5bc3cd72c82089209
[mirror_edk2.git] / StdLib / LibC / Uefi / Devices / Console / daConsole.c
1 /** @file
2 Abstract device driver for the UEFI Console.
3
4 Manipulates abstractions for stdin, stdout, stderr.
5
6 This device is a WIDE device and this driver returns WIDE
7 characters. It this the responsibility of the caller to convert between
8 narrow and wide characters in order to perform the desired operations.
9
10 The devices status as a wide device is indicatd by _S_IWTTY being set in
11 f_iflags.
12
13 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
14 This program and the accompanying materials are licensed and made available under
15 the terms and conditions of the BSD License that accompanies this distribution.
16 The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php.
18
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21
22 **/
23 #include <Uefi.h>
24 #include <Library/BaseLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Protocol/SimpleTextIn.h>
28 #include <Protocol/SimpleTextOut.h>
29
30 #include <LibConfig.h>
31
32 #include <errno.h>
33 #include <wctype.h>
34 #include <wchar.h>
35 #include <stdarg.h>
36 #include <sys/fcntl.h>
37 #include <unistd.h>
38 #include <kfile.h>
39 #include <Device/Device.h>
40 #include <Device/IIO.h>
41 #include <MainData.h>
42
43 static const CHAR16* const
44 stdioNames[NUM_SPECIAL] = {
45 L"stdin:", L"stdout:", L"stderr:"
46 };
47
48 static const int stdioFlags[NUM_SPECIAL] = {
49 O_RDONLY, // stdin
50 O_WRONLY, // stdout
51 O_WRONLY // stderr
52 };
53
54 static DeviceNode *ConNode[NUM_SPECIAL];
55 static ConInstance *ConInstanceList;
56
57 static cIIO *IIO;
58
59 /* Flags settable by Ioctl */
60 static BOOLEAN TtyCooked;
61 static BOOLEAN TtyEcho;
62
63 /** Convert string from MBCS to WCS and translate \n to \r\n.
64
65 It is the caller's responsibility to ensure that dest is
66 large enough to hold the converted results. It is guaranteed
67 that there will be fewer than n characters placed in dest.
68
69 @param[out] dest WCS buffer to receive the converted string.
70 @param[in] buf MBCS string to convert to WCS.
71 @param[in] n Number of BYTES contained in buf.
72 @param[in,out] Cs Pointer to the character state object for this stream
73
74 @return The number of BYTES consumed from buf.
75 **/
76 ssize_t
77 WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)
78 {
79 ssize_t i = 0;
80 int numB = 0;
81 wchar_t wc[2];
82
83 while(n > 0) {
84 numB = (int)mbrtowc(wc, buf, MIN(MB_LEN_MAX,n), Cs);
85 if( numB == 0) {
86 break;
87 };
88 if(numB < 0) { // If an unconvertable character, replace it.
89 wc[0] = BLOCKELEMENT_LIGHT_SHADE;
90 numB = 1;
91 }
92 if(wc[0] == L'\n') {
93 *dest++ = L'\r';
94 ++i;
95 }
96 *dest++ = (CHAR16)wc[0];
97 i += numB;
98 n -= numB;
99 buf += numB;
100 }
101 *dest = 0;
102 return i;
103 }
104
105 /** Close an open file.
106
107 @param[in] filp Pointer to the file descriptor structure for this file.
108
109 @retval 0 The file has been successfully closed.
110 @retval -1 filp does not point to a valid console descriptor.
111 **/
112 static
113 int
114 EFIAPI
115 da_ConClose(
116 IN struct __filedes *filp
117 )
118 {
119 ConInstance *Stream;
120
121 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
122 // Quick check to see if Stream looks reasonable
123 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
124 errno = EINVAL;
125 EFIerrno = RETURN_INVALID_PARAMETER;
126 return -1; // Looks like a bad File Descriptor pointer
127 }
128 gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed
129 return 0;
130 }
131
132 /** Position the console cursor to the coordinates specified by Position.
133
134 @param[in] filp Pointer to the file descriptor structure for this file.
135 @param[in] Position A value containing the target X and Y coordinates.
136 @param[in] whence Ignored by the Console device.
137
138 @retval Position Success. Returns a copy of the Position argument.
139 @retval -1 filp is not associated with a valid console stream.
140 @retval -1 This console stream is attached to stdin.
141 @retval -1 The SetCursorPosition operation failed.
142 **/
143 static
144 off_t
145 EFIAPI
146 da_ConSeek(
147 struct __filedes *filp,
148 off_t Position,
149 int whence ///< Ignored by Console
150 )
151 {
152 ConInstance *Stream;
153 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
154 XY_OFFSET CursorPos;
155
156 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
157 // Quick check to see if Stream looks reasonable
158 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
159 EFIerrno = RETURN_INVALID_PARAMETER;
160 return -1; // Looks like a bad This pointer
161 }
162 if(Stream->InstanceNum == STDIN_FILENO) {
163 // Seek is not valid for stdin
164 EFIerrno = RETURN_UNSUPPORTED;
165 return -1;
166 }
167 // Everything is OK to do the final verification and "seek".
168 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
169 CursorPos.Offset = Position;
170
171 EFIerrno = Proto->SetCursorPosition(Proto,
172 (INTN)CursorPos.XYpos.Column,
173 (INTN)CursorPos.XYpos.Row);
174
175 if(RETURN_ERROR(EFIerrno)) {
176 return -1;
177 }
178 else {
179 return Position;
180 }
181 }
182
183 /* Write a NULL terminated WCS to the EFI console.
184
185 NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters received
186 by da_ConWrite are WIDE characters. It is the responsibility of the
187 higher-level function(s) to perform any necessary conversions.
188
189 @param[in,out] BufferSize Number of characters in Buffer.
190 @param[in] Buffer The WCS string to be displayed
191
192 @return The number of Characters written.
193 */
194 static
195 ssize_t
196 EFIAPI
197 da_ConWrite(
198 IN struct __filedes *filp,
199 IN off_t *Position,
200 IN size_t BufferSize,
201 IN const void *Buffer
202 )
203 {
204 EFI_STATUS Status;
205 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
206 ConInstance *Stream;
207 ssize_t NumChar;
208 XY_OFFSET CursorPos;
209
210 NumChar = -1;
211 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
212 // Quick check to see if Stream looks reasonable
213 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
214 EFIerrno = RETURN_INVALID_PARAMETER;
215 return -1; // Looks like a bad This pointer
216 }
217 if(Stream->InstanceNum == STDIN_FILENO) {
218 // Write is not valid for stdin
219 EFIerrno = RETURN_UNSUPPORTED;
220 return -1;
221 }
222 // Everything is OK to do the write.
223 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
224
225 Status = EFI_SUCCESS;
226 if(Position != NULL) {
227 CursorPos.Offset = *Position;
228
229 Status = Proto->SetCursorPosition(Proto,
230 (INTN)CursorPos.XYpos.Column,
231 (INTN)CursorPos.XYpos.Row);
232
233 }
234 if(!RETURN_ERROR(Status)) {
235 // Send the Unicode buffer to the console
236 Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);
237 }
238
239 // Depending on status, update BufferSize and return
240 if(!RETURN_ERROR(Status)) {
241 //BufferSize = NumChar;
242 NumChar = BufferSize;
243 Stream->NumWritten += NumChar;
244 }
245 EFIerrno = Status; // Make error reason available to caller
246 return NumChar;
247 }
248
249 /** Read a wide character from the console input device.
250
251 NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters returned
252 by da_ConRead are WIDE characters. It is the responsibility of the
253 higher-level function(s) to perform any necessary conversions.
254
255 @param[in,out] BufferSize Number of characters in Buffer.
256 @param[in] filp Pointer to file descriptor for this file.
257 @param[in] offset Ignored.
258 @param[in] BufferSize Buffer size, in bytes.
259 @param[out] Buffer Buffer in which to place the read characters.
260
261 @retval -1 An error has occurred. Reason in errno and EFIerrno.
262 @retval -1 No data is available. errno is set to EAGAIN
263 @retval 1 One wide character has been placed in Buffer
264 **/
265 static
266 ssize_t
267 EFIAPI
268 da_ConRead(
269 IN OUT struct __filedes *filp,
270 IN OUT off_t *offset, // Console ignores this
271 IN size_t BufferSize,
272 OUT VOID *Buffer
273 )
274 {
275 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
276 ConInstance *Stream;
277 cIIO *Self;
278 EFI_INPUT_KEY Key = {0,0};
279 EFI_STATUS Status = RETURN_SUCCESS;
280 UINTN Edex;
281 ssize_t NumRead;
282 int Flags;
283 wchar_t RetChar; // Default to No Data
284
285 NumRead = -1;
286 if(BufferSize < sizeof(wchar_t)) {
287 errno = EINVAL; // Buffer is too small to hold one character
288 }
289 else {
290 Self = (cIIO *)filp->devdata;
291 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
292 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
293 Flags = filp->Oflags;
294 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
295 // No data pending in the Un-get buffer. Get a char from the hardware.
296 if((Flags & O_NONBLOCK) == 0) {
297 // Read a byte in Blocking mode
298 Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
299 EFIerrno = Status;
300 if(Status != EFI_SUCCESS) {
301 errno = EINVAL;
302 }
303 else {
304 Status = Proto->ReadKeyStroke(Proto, &Key);
305 if(Status == EFI_SUCCESS) {
306 NumRead = 1; // Indicate that Key holds the data
307 }
308 else {
309 errno = EIO;
310 }
311 }
312 }
313 else {
314 // Read a byte in Non-Blocking mode
315 Status = Proto->ReadKeyStroke(Proto, &Key);
316 EFIerrno = Status;
317 if(Status == EFI_SUCCESS) {
318 // Got a keystroke.
319 NumRead = 1; // Indicate that Key holds the data
320 }
321 else if(Status == EFI_NOT_READY) {
322 // Keystroke data is not available
323 errno = EAGAIN;
324 }
325 else {
326 // Hardware error
327 errno = EIO;
328 }
329 }
330 }
331 else {
332 // Use the data in the Un-get buffer
333 Key.ScanCode = Stream->UnGetKey.ScanCode;
334 Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;
335 Stream->UnGetKey.ScanCode = SCAN_NULL;
336 Stream->UnGetKey.UnicodeChar = CHAR_NULL;
337 NumRead = 1; // Indicate that Key holds the data
338 }
339 // If we have data, prepare it for return.
340 if(NumRead == 1) {
341 RetChar = Key.UnicodeChar;
342 if((RetChar == 0) && ((Self->Termio.c_iflag & IGNSPEC) == 0)) {
343 // Must be a control, function, or other non-printable key.
344 // Map it into the Platform portion of the Unicode private use area
345 RetChar = (Key.ScanCode == 0) ? 0 : 0xF900U - Key.ScanCode;
346 }
347 *((wchar_t *)Buffer) = RetChar;
348 }
349 }
350 return NumRead;
351 }
352
353 /** Console-specific helper function for the fstat() function.
354
355 st_size Set to number of characters read for stdin and number written for stdout and stderr.
356 st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode.
357 st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr
358 st_blksize Set to 1 since this is a character device
359
360 All other members of the stat structure are left unchanged.
361
362 @param[in] filp Pointer to file descriptor for this file.
363 @param[out] Buffer Pointer to a stat structure to receive the information.
364 @param[in,out] Something Ignored.
365
366 @retval 0 Successful completion.
367 @retval -1 Either filp is not associated with a console stream, or
368 Buffer is NULL. errno is set to EINVAL.
369 **/
370 static
371 int
372 EFIAPI
373 da_ConStat(
374 struct __filedes *filp,
375 struct stat *Buffer,
376 void *Something
377 )
378 {
379 ConInstance *Stream;
380 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
381 XY_OFFSET CursorPos;
382 INT32 OutMode;
383 UINTN ModeCol;
384 UINTN ModeRow;
385
386 // ConGetInfo
387 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
388 // Quick check to see if Stream looks reasonable
389 if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'
390 (Buffer == NULL))
391 {
392 errno = EINVAL;
393 EFIerrno = RETURN_INVALID_PARAMETER;
394 return -1;
395 }
396 // All of our parameters are correct, so fill in the information.
397 Buffer->st_blksize = 0; // Character device, not a block device
398 Buffer->st_mode = filp->f_iflags;
399
400 // ConGetPosition
401 if(Stream->InstanceNum == STDIN_FILENO) {
402 // This is stdin
403 Buffer->st_curpos = 0;
404 Buffer->st_size = (off_t)Stream->NumRead;
405 Buffer->st_physsize = 1;
406 }
407 else {
408 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
409 CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;
410 CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;
411 Buffer->st_curpos = (off_t)CursorPos.Offset;
412 Buffer->st_size = (off_t)Stream->NumWritten;
413
414 OutMode = Proto->Mode->Mode;
415 EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);
416 if(RETURN_ERROR(EFIerrno)) {
417 Buffer->st_physsize = 0;
418 }
419 else {
420 CursorPos.XYpos.Column = (UINT32)ModeCol;
421 CursorPos.XYpos.Row = (UINT32)ModeRow;
422 Buffer->st_physsize = (off_t)CursorPos.Offset;
423 }
424 }
425 return 0;
426 }
427
428 /** Console-specific helper for the ioctl system call.
429
430 The console device does not directly participate in ioctl operations.
431 This function completes the device abstraction and returns an error value
432 to indicate that the function is not supported for this device.
433
434 @retval -1 Function is not supported for this device.
435 **/
436 static
437 int
438 EFIAPI
439 da_ConIoctl(
440 struct __filedes *filp,
441 ULONGN cmd,
442 va_list argp
443 )
444 {
445 errno = ENODEV;
446 return -1;
447 }
448
449 /** Open an abstract Console Device.
450
451 @param[in] DevNode Pointer to the Device control structure for this stream.
452 @param[in] filp Pointer to the new file control structure for this stream.
453 @param[in] DevInstance Not used for the console device.
454 @param[in] Path Not used for the console device.
455 @param[in] MPath Not used for the console device.
456
457 @retval 0 This console stream has been successfully opened.
458 @retval -1 The DevNode or filp pointer is NULL.
459 @retval -1 DevNode does not point to a valid console stream device.
460 **/
461 int
462 EFIAPI
463 da_ConOpen(
464 DeviceNode *DevNode,
465 struct __filedes *filp,
466 int DevInstance, // Not used for console devices
467 wchar_t *Path, // Not used for console devices
468 wchar_t *MPath // Not used for console devices
469 )
470 {
471 ConInstance *Stream;
472 UINT32 Instance;
473 int RetVal = -1;
474
475 if((filp != NULL) &&
476 (DevNode != NULL))
477 {
478 Stream = (ConInstance *)DevNode->InstanceList;
479 // Quick check to see if Stream looks reasonable
480 if(Stream->Cookie == CON_COOKIE)
481 {
482 Instance = Stream->InstanceNum;
483 if(Instance < NUM_SPECIAL) {
484 gMD->StdIo[Instance] = Stream;
485 filp->f_iflags |= (_S_IFCHR | _S_ITTY | _S_IWTTY | _S_ICONSOLE);
486 filp->f_offset = 0;
487 filp->f_ops = &Stream->Abstraction;
488 filp->devdata = (void *)IIO;
489 RetVal = 0;
490 }
491 }
492 }
493 if (RetVal < 0) {
494 EFIerrno = RETURN_INVALID_PARAMETER;
495 errno = EINVAL;
496 }
497 return RetVal;
498
499 }
500
501 #include <sys/poll.h>
502 /* Returns a bit mask describing which operations could be completed immediately.
503
504 Testable Events for this device are:
505 (POLLIN | POLLRDNORM) A Unicode character is available to read
506 (POLLIN) A ScanCode is ready.
507 (POLLOUT) The device is ready for output - always set on stdout and stderr.
508
509 Non-testable Events which are only valid in return values are:
510 POLLERR The specified device is not one of stdin, stdout, or stderr.
511 POLLHUP The specified stream has been disconnected
512 POLLNVAL da_ConPoll was called with an invalid parameter.
513
514 NOTE: The "Events" handled by this function are not UEFI events.
515
516 @param[in] filp Pointer to the file control structure for this stream.
517 @param[in] events A bit mask identifying the events to be examined
518 for this device.
519
520 @return Returns a bit mask comprised of both testable and non-testable
521 event codes indicating both the state of the operation and the
522 status of the device.
523 */
524 static
525 short
526 EFIAPI
527 da_ConPoll(
528 struct __filedes *filp,
529 short events
530 )
531 {
532 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
533 ConInstance *Stream;
534 EFI_STATUS Status = RETURN_SUCCESS;
535 short RdyMask = 0;
536
537 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
538 // Quick check to see if Stream looks reasonable
539 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
540 errno = EINVAL;
541 EFIerrno = RETURN_INVALID_PARAMETER;
542 return POLLNVAL; // Looks like a bad filp pointer
543 }
544 if(Stream->InstanceNum == 0) {
545 // Only input is supported for this device
546 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
547 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
548 Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey);
549 if(Status == RETURN_SUCCESS) {
550 RdyMask = POLLIN;
551 if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) {
552 RdyMask |= POLLRDNORM;
553 }
554 }
555 else {
556 Stream->UnGetKey.ScanCode = SCAN_NULL;
557 Stream->UnGetKey.UnicodeChar = CHAR_NULL;
558 }
559 }
560 }
561 else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2?
562 // Only output is supported for this device
563 RdyMask = POLLOUT;
564 }
565 else {
566 RdyMask = POLLERR; // Not one of the standard streams
567 }
568 EFIerrno = Status;
569
570 return (RdyMask & (events | POLL_RETONLY));
571 }
572
573 /** Construct the Console stream devices: stdin, stdout, stderr.
574
575 Allocate the instance structure and populate it with the information for
576 each stream device.
577 **/
578 RETURN_STATUS
579 EFIAPI
580 __Cons_construct(
581 IN EFI_HANDLE ImageHandle,
582 IN EFI_SYSTEM_TABLE *SystemTable
583 )
584 {
585 ConInstance *Stream;
586 RETURN_STATUS Status;
587 int i;
588
589 Status = RETURN_OUT_OF_RESOURCES;
590 ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));
591 if(ConInstanceList != NULL) {
592 IIO = New_cIIO();
593 if(IIO == NULL) {
594 FreePool(ConInstanceList);
595 }
596 else {
597 Status = RETURN_SUCCESS;
598 for( i = 0; i < NUM_SPECIAL; ++i) {
599 // Get pointer to instance.
600 Stream = &ConInstanceList[i];
601
602 Stream->Cookie = CON_COOKIE;
603 Stream->InstanceNum = i;
604 Stream->CharState.A = 0; // Start in the initial state
605
606 switch(i) {
607 case STDIN_FILENO:
608 Stream->Dev = SystemTable->ConIn;
609 break;
610 case STDOUT_FILENO:
611 Stream->Dev = SystemTable->ConOut;
612 break;
613 case STDERR_FILENO:
614 if(SystemTable->StdErr == NULL) {
615 Stream->Dev = SystemTable->ConOut;
616 }
617 else {
618 Stream->Dev = SystemTable->StdErr;
619 }
620 break;
621 default:
622 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.
623 }
624
625 Stream->Abstraction.fo_close = &da_ConClose;
626 Stream->Abstraction.fo_read = &da_ConRead;
627 Stream->Abstraction.fo_write = &da_ConWrite;
628 Stream->Abstraction.fo_stat = &da_ConStat;
629 Stream->Abstraction.fo_lseek = &da_ConSeek;
630 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;
631 Stream->Abstraction.fo_ioctl = &da_ConIoctl;
632 Stream->Abstraction.fo_poll = &da_ConPoll;
633 Stream->Abstraction.fo_flush = &fnullop_flush;
634 Stream->Abstraction.fo_delete = &fbadop_delete;
635 Stream->Abstraction.fo_mkdir = &fbadop_mkdir;
636 Stream->Abstraction.fo_rmdir = &fbadop_rmdir;
637 Stream->Abstraction.fo_rename = &fbadop_rename;
638
639 Stream->NumRead = 0;
640 Stream->NumWritten = 0;
641 Stream->UnGetKey.ScanCode = SCAN_NULL;
642 Stream->UnGetKey.UnicodeChar = CHAR_NULL;
643
644 if(Stream->Dev == NULL) {
645 continue; // No device for this stream.
646 }
647 ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,
648 1, sizeof(ConInstance), stdioFlags[i]);
649 if(ConNode[i] == NULL) {
650 Status = EFIerrno; // Grab error code that DevRegister produced.
651 break;
652 }
653 Stream->Parent = ConNode[i];
654 }
655 /* Initialize Ioctl flags until Ioctl is really implemented. */
656 TtyCooked = TRUE;
657 TtyEcho = TRUE;
658 }
659 }
660 return Status;
661 }
662
663 RETURN_STATUS
664 EFIAPI
665 __Cons_deconstruct(
666 IN EFI_HANDLE ImageHandle,
667 IN EFI_SYSTEM_TABLE *SystemTable
668 )
669 {
670 int i;
671
672 for(i = 0; i < NUM_SPECIAL; ++i) {
673 if(ConNode[i] != NULL) {
674 FreePool(ConNode[i]);
675 }
676 }
677 if(ConInstanceList != NULL) {
678 FreePool(ConInstanceList);
679 }
680 if(IIO != NULL) {
681 IIO->Delete(IIO);
682 IIO = NULL;
683 }
684
685 return RETURN_SUCCESS;
686 }
687
688 /* ######################################################################### */
689 #if 0 /* Not implemented (yet?) for Console */
690
691 static
692 int
693 EFIAPI
694 da_ConCntl(
695 struct __filedes *filp,
696 UINT32,
697 void *,
698 void *
699 )
700 {
701 }
702
703 static
704 int
705 EFIAPI
706 da_ConFlush(
707 struct __filedes *filp
708 )
709 {
710 return 0;
711 }
712 #endif /* Not implemented for Console */