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