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 */ 826