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