mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 07:17:27 +00:00 
			
		
		
		
	 4b2cf923c0
			
		
	
	
		4b2cf923c0
		
	
	
	
	
		
			
			AppPkg.dsc: Remove IPF support and add NOOPT build target. StdLib.dsc: Add NOOPT build target. daConsole.c: Cast a comparison to BOOLEAN before assigning it to a BOOLEAN. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Daryl McDaniel <daryl.mcdaniel@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16331 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			766 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			766 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Abstract device driver for the UEFI Console.
 | |
| 
 | |
|   Manipulates abstractions for stdin, stdout, stderr.
 | |
| 
 | |
|   This device is a WIDE device and this driver returns WIDE
 | |
|   characters.  It this the responsibility of the caller to convert between
 | |
|   narrow and wide characters in order to perform the desired operations.
 | |
| 
 | |
|   The devices status as a wide device is indicatd by _S_IWTTY being set in
 | |
|   f_iflags.
 | |
| 
 | |
|   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials are licensed and made available under
 | |
|   the terms and conditions of the BSD License that accompanies this distribution.
 | |
|   The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| #include  <Uefi.h>
 | |
| #include  <Library/BaseLib.h>
 | |
| #include  <Library/MemoryAllocationLib.h>
 | |
| #include  <Library/UefiBootServicesTableLib.h>
 | |
| #include  <Library/DebugLib.h>
 | |
| #include  <Protocol/SimpleTextIn.h>
 | |
| #include  <Protocol/SimpleTextOut.h>
 | |
| 
 | |
| #include  <LibConfig.h>
 | |
| 
 | |
| #include  <errno.h>
 | |
| #include  <wctype.h>
 | |
| #include  <wchar.h>
 | |
| #include  <stdarg.h>
 | |
| #include  <sys/fcntl.h>
 | |
| #include  <unistd.h>
 | |
| #include  <sys/termios.h>
 | |
| #include  <kfile.h>
 | |
| #include  <Device/Device.h>
 | |
| #include  <Device/IIO.h>
 | |
| #include  <MainData.h>
 | |
| 
 | |
| static const CHAR16* const
 | |
| stdioNames[NUM_SPECIAL]   = {
 | |
|   L"stdin:", L"stdout:", L"stderr:"
 | |
| };
 | |
| 
 | |
| static const int stdioFlags[NUM_SPECIAL] = {
 | |
|   O_RDONLY,             // stdin
 | |
|   O_WRONLY,             // stdout
 | |
|   O_WRONLY              // stderr
 | |
| };
 | |
| 
 | |
| static DeviceNode    *ConNode[NUM_SPECIAL];
 | |
| static ConInstance   *ConInstanceList;
 | |
| 
 | |
| static cIIO          *IIO;
 | |
| 
 | |
| /* Flags settable by Ioctl */
 | |
| static BOOLEAN        TtyCooked;
 | |
| static BOOLEAN        TtyEcho;
 | |
| 
 | |
| /** Convert string from MBCS to WCS and translate \n to \r\n.
 | |
| 
 | |
|     It is the caller's responsibility to ensure that dest is
 | |
|     large enough to hold the converted results.  It is guaranteed
 | |
|     that there will be fewer than n characters placed in dest.
 | |
| 
 | |
|     @param[out]     dest    WCS buffer to receive the converted string.
 | |
|     @param[in]      buf     MBCS string to convert to WCS.
 | |
|     @param[in]      n       Number of BYTES contained in buf.
 | |
|     @param[in,out]  Cs      Pointer to the character state object for this stream
 | |
| 
 | |
|     @return   The number of BYTES consumed from buf.
 | |
| **/
 | |
| ssize_t
 | |
| WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)
 | |
| {
 | |
|   ssize_t i     = 0;
 | |
|   int     numB  = 0;
 | |
|   wchar_t wc[2];
 | |
| 
 | |
|   while(n > 0) {
 | |
|     numB = (int)mbrtowc(wc, buf, MIN(MB_LEN_MAX,n), Cs);
 | |
|     if( numB == 0) {
 | |
|       break;
 | |
|     };
 | |
|     if(numB < 0) {    // If an unconvertable character, replace it.
 | |
|       wc[0] = BLOCKELEMENT_LIGHT_SHADE;
 | |
|       numB = 1;
 | |
|     }
 | |
|     if(wc[0] == L'\n') {
 | |
|       *dest++ = L'\r';
 | |
|       ++i;
 | |
|     }
 | |
|     *dest++ = (CHAR16)wc[0];
 | |
|     i += numB;
 | |
|     n -= numB;
 | |
|     buf += numB;
 | |
|   }
 | |
|   *dest = 0;
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| /** Close an open file.
 | |
| 
 | |
|     @param[in]  filp    Pointer to the file descriptor structure for this file.
 | |
| 
 | |
|     @retval   0     The file has been successfully closed.
 | |
|     @retval   -1    filp does not point to a valid console descriptor.
 | |
| **/
 | |
| static
 | |
| int
 | |
| EFIAPI
 | |
| da_ConClose(
 | |
|   IN      struct __filedes   *filp
 | |
| )
 | |
| {
 | |
|   ConInstance    *Stream;
 | |
| 
 | |
|   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
 | |
|     errno     = EINVAL;
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     return -1;    // Looks like a bad File Descriptor pointer
 | |
|   }
 | |
|   gMD->StdIo[Stream->InstanceNum] = NULL;   // Mark the stream as closed
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /** Position the console cursor to the coordinates specified by Position.
 | |
| 
 | |
|     @param[in]  filp      Pointer to the file descriptor structure for this file.
 | |
|     @param[in]  Position  A value containing the target X and Y coordinates.
 | |
|     @param[in]  whence    Ignored by the Console device.
 | |
| 
 | |
|     @retval   Position    Success.  Returns a copy of the Position argument.
 | |
|     @retval   -1          filp is not associated with a valid console stream.
 | |
|     @retval   -1          This console stream is attached to stdin.
 | |
|     @retval   -1          The SetCursorPosition operation failed.
 | |
| **/
 | |
| static
 | |
| off_t
 | |
| EFIAPI
 | |
| da_ConSeek(
 | |
|   struct __filedes   *filp,
 | |
|   off_t               Position,
 | |
|   int                 whence      ///< Ignored by Console
 | |
| )
 | |
| {
 | |
|   ConInstance                       *Stream;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *Proto;
 | |
|   XY_OFFSET                          CursorPos;
 | |
| 
 | |
|   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     return -1;    // Looks like a bad This pointer
 | |
|   }
 | |
|   if(Stream->InstanceNum == STDIN_FILENO) {
 | |
|     // Seek is not valid for stdin
 | |
|     EFIerrno = RETURN_UNSUPPORTED;
 | |
|     return -1;
 | |
|   }
 | |
|   // Everything is OK to do the final verification and "seek".
 | |
|   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
 | |
|   CursorPos.Offset = Position;
 | |
| 
 | |
|   EFIerrno = Proto->SetCursorPosition(Proto,
 | |
|                                       (INTN)CursorPos.XYpos.Column,
 | |
|                                       (INTN)CursorPos.XYpos.Row);
 | |
| 
 | |
|   if(RETURN_ERROR(EFIerrno)) {
 | |
|     return -1;
 | |
|   }
 | |
|   else {
 | |
|     return Position;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* Write a NULL terminated WCS to the EFI console.
 | |
| 
 | |
|   NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters received
 | |
|         by da_ConWrite are WIDE characters.  It is the responsibility of the
 | |
|         higher-level function(s) to perform any necessary conversions.
 | |
| 
 | |
|     @param[in,out]  BufferSize  Number of characters in Buffer.
 | |
|   @param[in]      Buffer      The WCS string to be displayed
 | |
| 
 | |
|     @return   The number of Characters written.
 | |
| */
 | |
| static
 | |
| ssize_t
 | |
| EFIAPI
 | |
| da_ConWrite(
 | |
|   IN  struct __filedes     *filp,
 | |
|   IN  off_t                *Position,
 | |
|   IN  size_t                BufferSize,
 | |
|   IN  const void           *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
 | |
|   ConInstance                        *Stream;
 | |
|   ssize_t                             NumChar;
 | |
|   XY_OFFSET                          CursorPos;
 | |
| 
 | |
|   NumChar = -1;
 | |
|   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     return -1;    // Looks like a bad This pointer
 | |
|   }
 | |
|   if(Stream->InstanceNum == STDIN_FILENO) {
 | |
|     // Write is not valid for stdin
 | |
|     EFIerrno = RETURN_UNSUPPORTED;
 | |
|     return -1;
 | |
|   }
 | |
|   // Everything is OK to do the write.
 | |
|   Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   if(Position != NULL) {
 | |
|     CursorPos.Offset = *Position;
 | |
| 
 | |
|     Status = Proto->SetCursorPosition(Proto,
 | |
|                                       (INTN)CursorPos.XYpos.Column,
 | |
|                                       (INTN)CursorPos.XYpos.Row);
 | |
| 
 | |
|   }
 | |
|   if(!RETURN_ERROR(Status)) {
 | |
|   // Send the Unicode buffer to the console
 | |
|     Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);
 | |
|   }
 | |
| 
 | |
|   // Depending on status, update BufferSize and return
 | |
|   if(!RETURN_ERROR(Status)) {
 | |
|     NumChar = BufferSize;
 | |
|     Stream->NumWritten += NumChar;
 | |
|   }
 | |
|   EFIerrno = Status;      // Make error reason available to caller
 | |
|   return NumChar;
 | |
| }
 | |
| 
 | |
| /** Read a wide character from the console input device.
 | |
| 
 | |
|     Returns NUL or a translated input character.
 | |
| 
 | |
|     @param[in]      filp          Pointer to file descriptor for this file.
 | |
|     @param[out]     Buffer        Buffer in which to place the read character.
 | |
| 
 | |
|     @retval    EFI_DEVICE_ERROR   A hardware error has occurred.
 | |
|     @retval    EFI_NOT_READY      No data is available.  Try again later.
 | |
|     @retval    EFI_SUCCESS        One wide character has been placed in Character
 | |
|                                     - 0x0000  NUL, ignore this
 | |
|                                     - Otherwise, should be a good wide character in Character
 | |
| **/
 | |
| static
 | |
| EFI_STATUS
 | |
| da_ConRawRead (
 | |
|   IN OUT  struct __filedes   *filp,
 | |
|      OUT  wchar_t            *Character
 | |
| )
 | |
| {
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *Proto;
 | |
|   ConInstance                      *Stream;
 | |
|   cIIO                             *Self;
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_INPUT_KEY                     Key = {0,0};
 | |
|   wchar_t                           RetChar;
 | |
| 
 | |
|   Self    = (cIIO *)filp->devdata;
 | |
|   Stream  = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   Proto   = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
 | |
| 
 | |
|   if(Stream->UnGetKey == CHAR_NULL) {
 | |
|     Status = Proto->ReadKeyStroke(Proto, &Key);
 | |
|   }
 | |
|   else {
 | |
|     Status  = EFI_SUCCESS;
 | |
|     // Use the data in the Un-get buffer
 | |
|     // Guaranteed that ScanCode and UnicodeChar are not both NUL
 | |
|     Key.ScanCode        = SCAN_NULL;
 | |
|     Key.UnicodeChar     = Stream->UnGetKey;
 | |
|     Stream->UnGetKey    = CHAR_NULL;
 | |
|   }
 | |
|   if(Status == EFI_SUCCESS) {
 | |
|     // Translate the Escape Scan Code to an ESC character
 | |
|     if (Key.ScanCode != 0) {
 | |
|       if (Key.ScanCode == SCAN_ESC) {
 | |
|         RetChar = CHAR_ESC;
 | |
|       }
 | |
|       else if((Self->Termio.c_iflag & IGNSPEC) != 0) {
 | |
|         // If we are ignoring special characters, return a NUL
 | |
|         RetChar = 0;
 | |
|       }
 | |
|       else {
 | |
|         // Must be a control, function, or other non-printable key.
 | |
|         // Map it into the Platform portion of the Unicode private use area
 | |
|         RetChar = TtyFunKeyMax - Key.ScanCode;
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       RetChar = Key.UnicodeChar;
 | |
|     }
 | |
|     *Character = RetChar;
 | |
|   }
 | |
|   else {
 | |
|     *Character = 0;
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Read a wide character from the console input device.
 | |
| 
 | |
|   NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters returned
 | |
|         by da_ConRead are WIDE characters.  It is the responsibility of the
 | |
|         higher-level function(s) to perform any necessary conversions.
 | |
| 
 | |
|     A NUL character, 0x0000, is never returned.  In the event that such a character
 | |
|     is encountered, the read is either retried or -1 is returned with errno set
 | |
|     to EAGAIN.
 | |
| 
 | |
|     @param[in]      filp          Pointer to file descriptor for this file.
 | |
|     @param[in]      offset        Ignored.
 | |
|     @param[in]      BufferSize    Buffer size, in bytes.
 | |
|     @param[out]     Buffer        Buffer in which to place the read characters.
 | |
| 
 | |
|     @retval    -1   An error has occurred.  Reason in errno and EFIerrno.
 | |
|     @retval    -1   No data is available.  errno is set to EAGAIN
 | |
|     @retval     1   One wide character has been placed in Buffer
 | |
| **/
 | |
| static
 | |
| ssize_t
 | |
| EFIAPI
 | |
| da_ConRead(
 | |
|   IN OUT  struct __filedes   *filp,
 | |
|   IN OUT  off_t              *offset,         // Console ignores this
 | |
|   IN      size_t              BufferSize,
 | |
|      OUT  VOID               *Buffer
 | |
| )
 | |
| {
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *Proto;
 | |
|   ConInstance                      *Stream;
 | |
|   //cIIO                              *Self;
 | |
|   EFI_STATUS                        Status;
 | |
|   UINTN                             Edex;
 | |
|   ssize_t                           NumRead;
 | |
|   BOOLEAN                           BlockingMode;
 | |
|   wchar_t                           RetChar;
 | |
| 
 | |
|   NumRead = -1;
 | |
|   if(BufferSize < sizeof(wchar_t)) {
 | |
|     errno = EINVAL;     // Buffer is too small to hold one character
 | |
|   }
 | |
|   else {
 | |
|     Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|     Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
 | |
|     BlockingMode = (BOOLEAN)((filp->Oflags & O_NONBLOCK) == 0);
 | |
| 
 | |
|     do {
 | |
|       Status = EFI_SUCCESS;
 | |
|       if(BlockingMode) {
 | |
|         // Read a byte in Blocking mode
 | |
|         Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
 | |
|       }
 | |
| 
 | |
|       /*  WaitForEvent should not be able to fail since
 | |
|             NumberOfEvents is set to constant 1 so is never 0
 | |
|             Event is set by the Simple Text Input protocol so should never be EVT_NOTIFY_SIGNAL
 | |
|             Current TPL should be TPL_APPLICATION.
 | |
|           ASSERT so that we catch any problems during development.
 | |
|       */
 | |
|       ASSERT(Status == EFI_SUCCESS);
 | |
| 
 | |
|       Status = da_ConRawRead (filp, &RetChar);
 | |
|     } while ( BlockingMode &&
 | |
|              (RetChar == 0) &&
 | |
|              (Status != EFI_DEVICE_ERROR));
 | |
| 
 | |
|     EFIerrno = Status;
 | |
|     if(Status == EFI_SUCCESS) {
 | |
|       // Got a keystroke.
 | |
|       NumRead = 1;   // Indicate that Key holds the data
 | |
|     }
 | |
|     else if(Status == EFI_NOT_READY) {
 | |
|       // Keystroke data is not available
 | |
|       errno = EAGAIN;
 | |
|     }
 | |
|     else {
 | |
|       // Hardware error
 | |
|       errno = EIO;
 | |
|     }
 | |
|     if (RetChar == 0) {
 | |
|       NumRead = -1;
 | |
|       errno = EAGAIN;
 | |
|     }
 | |
|     else {
 | |
|       *((wchar_t *)Buffer) = RetChar;
 | |
|     }
 | |
|   }
 | |
|   return NumRead;
 | |
| }
 | |
| 
 | |
| /** Console-specific helper function for the fstat() function.
 | |
| 
 | |
|     st_size       Set to number of characters read for stdin and number written for stdout and stderr.
 | |
|     st_physsize   1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode.
 | |
|     st_curpos     0 for stdin, current X & Y coordinates for stdout and stderr
 | |
|     st_blksize    Set to 1 since this is a character device
 | |
| 
 | |
|     All other members of the stat structure are left unchanged.
 | |
| 
 | |
|     @param[in]      filp          Pointer to file descriptor for this file.
 | |
|     @param[out]     Buffer        Pointer to a stat structure to receive the information.
 | |
|     @param[in,out]  Something     Ignored.
 | |
| 
 | |
|     @retval   0   Successful completion.
 | |
|     @retval   -1  Either filp is not associated with a console stream, or
 | |
|                   Buffer is NULL.  errno is set to EINVAL.
 | |
| **/
 | |
| static
 | |
| int
 | |
| EFIAPI
 | |
| da_ConStat(
 | |
|   struct __filedes   *filp,
 | |
|   struct stat        *Buffer,
 | |
|   void               *Something
 | |
|   )
 | |
| {
 | |
|   ConInstance                        *Stream;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *Proto;
 | |
|   XY_OFFSET                           CursorPos;
 | |
|   INT32                               OutMode;
 | |
|   UINTN                               ModeCol;
 | |
|   UINTN                               ModeRow;
 | |
| 
 | |
| // ConGetInfo
 | |
|   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|   if ((Stream->Cookie != CON_COOKIE) ||    // Cookie == 'IoAb'
 | |
|       (Buffer == NULL))
 | |
|   {
 | |
|     errno     = EINVAL;
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     return -1;
 | |
|   }
 | |
|   // All of our parameters are correct, so fill in the information.
 | |
|   Buffer->st_blksize  = 0;   // Character device, not a block device
 | |
|   Buffer->st_mode     = filp->f_iflags;
 | |
| 
 | |
| // ConGetPosition
 | |
|   if(Stream->InstanceNum == STDIN_FILENO) {
 | |
|     // This is stdin
 | |
|     Buffer->st_curpos    = 0;
 | |
|     Buffer->st_size      = (off_t)Stream->NumRead;
 | |
|     Buffer->st_physsize  = 1;
 | |
|   }
 | |
|   else {
 | |
|     Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
 | |
|     CursorPos.XYpos.Column  = (UINT32)Proto->Mode->CursorColumn;
 | |
|     CursorPos.XYpos.Row     = (UINT32)Proto->Mode->CursorRow;
 | |
|     Buffer->st_curpos       = (off_t)CursorPos.Offset;
 | |
|     Buffer->st_size         = (off_t)Stream->NumWritten;
 | |
| 
 | |
|     OutMode  = Proto->Mode->Mode;
 | |
|     EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);
 | |
|     if(RETURN_ERROR(EFIerrno)) {
 | |
|       Buffer->st_physsize = 0;
 | |
|     }
 | |
|     else {
 | |
|       CursorPos.XYpos.Column  = (UINT32)ModeCol;
 | |
|       CursorPos.XYpos.Row     = (UINT32)ModeRow;
 | |
|       Buffer->st_physsize     = (off_t)CursorPos.Offset;
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /** Console-specific helper for the ioctl system call.
 | |
| 
 | |
|     The console device does not directly participate in ioctl operations.
 | |
|     This function completes the device abstraction and returns an error value
 | |
|     to indicate that the function is not supported for this device.
 | |
| 
 | |
|     @retval   -1    Function is not supported for this device.
 | |
| **/
 | |
| static
 | |
| int
 | |
| EFIAPI
 | |
| da_ConIoctl(
 | |
|   struct __filedes   *filp,
 | |
|   ULONGN              cmd,
 | |
|   va_list             argp
 | |
|   )
 | |
| {
 | |
|   errno   = ENODEV;
 | |
|   return  -1;
 | |
| }
 | |
| 
 | |
| /** Open an abstract Console Device.
 | |
| 
 | |
|     @param[in]    DevNode       Pointer to the Device control structure for this stream.
 | |
|     @param[in]    filp          Pointer to the new file control structure for this stream.
 | |
|     @param[in]    DevInstance   Not used for the console device.
 | |
|     @param[in]    Path          Not used for the console device.
 | |
|     @param[in]    MPath         Not used for the console device.
 | |
| 
 | |
|     @retval   0   This console stream has been successfully opened.
 | |
|     @retval   -1  The DevNode or filp pointer is NULL.
 | |
|     @retval   -1  DevNode does not point to a valid console stream device.
 | |
| **/
 | |
| int
 | |
| EFIAPI
 | |
| da_ConOpen(
 | |
|   DeviceNode         *DevNode,
 | |
|   struct __filedes   *filp,
 | |
|   int                 DevInstance,    // Not used for console devices
 | |
|   wchar_t            *Path,           // Not used for console devices
 | |
|   wchar_t            *MPath           // Not used for console devices
 | |
|   )
 | |
| {
 | |
|   ConInstance                      *Stream;
 | |
|   UINT32          Instance;
 | |
|   int             RetVal = -1;
 | |
| 
 | |
|   if((filp    != NULL)    &&
 | |
|       (DevNode != NULL))
 | |
|   {
 | |
|   Stream = (ConInstance *)DevNode->InstanceList;
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|     if(Stream->Cookie == CON_COOKIE)
 | |
|     {
 | |
|       Instance = Stream->InstanceNum;
 | |
|       if(Instance < NUM_SPECIAL) {
 | |
|         gMD->StdIo[Instance] = Stream;
 | |
|         filp->f_iflags |= (_S_IFCHR | _S_ITTY | _S_IWTTY | _S_ICONSOLE);
 | |
|         filp->f_offset = 0;
 | |
|         filp->f_ops = &Stream->Abstraction;
 | |
|         filp->devdata = (void *)IIO;
 | |
|         RetVal = 0;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (RetVal < 0) {
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     errno = EINVAL;
 | |
|   }
 | |
|   return RetVal;
 | |
| 
 | |
| }
 | |
| 
 | |
| #include  <sys/poll.h>
 | |
| /*  Returns a bit mask describing which operations could be completed immediately.
 | |
| 
 | |
|     Testable Events for this device are:
 | |
|     (POLLIN | POLLRDNORM)   A Unicode character is available to read
 | |
|     (POLLIN)                A ScanCode is ready.
 | |
|     (POLLOUT)               The device is ready for output - always set on stdout and stderr.
 | |
| 
 | |
|     Non-testable Events which are only valid in return values are:
 | |
|       POLLERR                 The specified device is not one of stdin, stdout, or stderr.
 | |
|       POLLHUP                 The specified stream has been disconnected
 | |
|       POLLNVAL                da_ConPoll was called with an invalid parameter.
 | |
| 
 | |
|   NOTE: The "Events" handled by this function are not UEFI events.
 | |
| 
 | |
|     @param[in]  filp      Pointer to the file control structure for this stream.
 | |
|     @param[in]  events    A bit mask identifying the events to be examined
 | |
|                           for this device.
 | |
| 
 | |
|     @return   Returns a bit mask comprised of both testable and non-testable
 | |
|               event codes indicating both the state of the operation and the
 | |
|               status of the device.
 | |
| */
 | |
| static
 | |
| short
 | |
| EFIAPI
 | |
| da_ConPoll(
 | |
|   struct __filedes   *filp,
 | |
|   short              events
 | |
|   )
 | |
| {
 | |
|   ConInstance                      *Stream;
 | |
|   EFI_STATUS                        Status = RETURN_SUCCESS;
 | |
|   short                             RdyMask = 0;
 | |
| 
 | |
|   Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
 | |
|   // Quick check to see if Stream looks reasonable
 | |
|   if(Stream->Cookie != CON_COOKIE) {    // Cookie == 'IoAb'
 | |
|     errno     = EINVAL;
 | |
|     EFIerrno = RETURN_INVALID_PARAMETER;
 | |
|     return POLLNVAL;    // Looks like a bad filp pointer
 | |
|   }
 | |
|   if(Stream->InstanceNum == 0) {
 | |
|     // STDIN: Only input is supported for this device
 | |
|     Status = da_ConRawRead (filp, &Stream->UnGetKey);
 | |
|     if(Status == RETURN_SUCCESS) {
 | |
|       RdyMask = POLLIN;
 | |
|       if ((Stream->UnGetKey <  TtyFunKeyMin)   ||
 | |
|           (Stream->UnGetKey >= TtyFunKeyMax))
 | |
|       {
 | |
|         RdyMask |= POLLRDNORM;
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       Stream->UnGetKey  = CHAR_NULL;
 | |
|     }
 | |
|   }
 | |
|   else if(Stream->InstanceNum < NUM_SPECIAL) {  // Not 0, is it 1 or 2?
 | |
|     // (STDOUT || STDERR): Only output is supported for this device
 | |
|     RdyMask = POLLOUT;
 | |
|   }
 | |
|   else {
 | |
|     RdyMask = POLLERR;    // Not one of the standard streams
 | |
|   }
 | |
|   EFIerrno = Status;
 | |
| 
 | |
|   return (RdyMask & (events | POLL_RETONLY));
 | |
| }
 | |
| 
 | |
| /** Construct the Console stream devices: stdin, stdout, stderr.
 | |
| 
 | |
|     Allocate the instance structure and populate it with the information for
 | |
|     each stream device.
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| __Cons_construct(
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
| )
 | |
| {
 | |
|   ConInstance    *Stream;
 | |
|   RETURN_STATUS   Status;
 | |
|   int             i;
 | |
| 
 | |
|   Status = RETURN_OUT_OF_RESOURCES;
 | |
|   ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));
 | |
|   if(ConInstanceList != NULL) {
 | |
|     IIO = New_cIIO();
 | |
|     if(IIO == NULL) {
 | |
|       FreePool(ConInstanceList);
 | |
|   }
 | |
|     else {
 | |
|       Status = RETURN_SUCCESS;
 | |
|   for( i = 0; i < NUM_SPECIAL; ++i) {
 | |
|     // Get pointer to instance.
 | |
|     Stream = &ConInstanceList[i];
 | |
| 
 | |
|     Stream->Cookie      = CON_COOKIE;
 | |
|     Stream->InstanceNum = i;
 | |
|     Stream->CharState.A = 0;    // Start in the initial state
 | |
| 
 | |
|     switch(i) {
 | |
|       case STDIN_FILENO:
 | |
|         Stream->Dev = SystemTable->ConIn;
 | |
|         break;
 | |
|       case STDOUT_FILENO:
 | |
|         Stream->Dev = SystemTable->ConOut;
 | |
|         break;
 | |
|       case STDERR_FILENO:
 | |
|         if(SystemTable->StdErr == NULL) {
 | |
|           Stream->Dev = SystemTable->ConOut;
 | |
|         }
 | |
|         else {
 | |
|           Stream->Dev = SystemTable->StdErr;
 | |
|         }
 | |
|         break;
 | |
|       default:
 | |
|         return RETURN_VOLUME_CORRUPTED;     // This is a "should never happen" case.
 | |
|     }
 | |
| 
 | |
|     Stream->Abstraction.fo_close    = &da_ConClose;
 | |
|     Stream->Abstraction.fo_read     = &da_ConRead;
 | |
|     Stream->Abstraction.fo_write    = &da_ConWrite;
 | |
|     Stream->Abstraction.fo_stat     = &da_ConStat;
 | |
|     Stream->Abstraction.fo_lseek    = &da_ConSeek;
 | |
|     Stream->Abstraction.fo_fcntl    = &fnullop_fcntl;
 | |
|     Stream->Abstraction.fo_ioctl    = &da_ConIoctl;
 | |
|     Stream->Abstraction.fo_poll     = &da_ConPoll;
 | |
|     Stream->Abstraction.fo_flush    = &fnullop_flush;
 | |
|     Stream->Abstraction.fo_delete   = &fbadop_delete;
 | |
|     Stream->Abstraction.fo_mkdir    = &fbadop_mkdir;
 | |
|     Stream->Abstraction.fo_rmdir    = &fbadop_rmdir;
 | |
|     Stream->Abstraction.fo_rename   = &fbadop_rename;
 | |
| 
 | |
|     Stream->NumRead     = 0;
 | |
|     Stream->NumWritten  = 0;
 | |
|     Stream->UnGetKey    = CHAR_NULL;
 | |
| 
 | |
|     if(Stream->Dev == NULL) {
 | |
|       continue;                 // No device for this stream.
 | |
|     }
 | |
|         ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,
 | |
|                                    1, sizeof(ConInstance), stdioFlags[i]);
 | |
|     if(ConNode[i] == NULL) {
 | |
|           Status = EFIerrno;    // Grab error code that DevRegister produced.
 | |
|       break;
 | |
|     }
 | |
|     Stream->Parent = ConNode[i];
 | |
|   }
 | |
|   /* Initialize Ioctl flags until Ioctl is really implemented. */
 | |
|   TtyCooked = TRUE;
 | |
|   TtyEcho   = TRUE;
 | |
|     }
 | |
|   }
 | |
|   return  Status;
 | |
| }
 | |
| 
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| __Cons_deconstruct(
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
| )
 | |
| {
 | |
|   int   i;
 | |
| 
 | |
|   for(i = 0; i < NUM_SPECIAL; ++i) {
 | |
|     if(ConNode[i] != NULL) {
 | |
|       FreePool(ConNode[i]);
 | |
|     }
 | |
|   }
 | |
|   if(ConInstanceList != NULL) {
 | |
|     FreePool(ConInstanceList);
 | |
|   }
 | |
|   if(IIO != NULL) {
 | |
|     IIO->Delete(IIO);
 | |
|     IIO = NULL;
 | |
|   }
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| /* ######################################################################### */
 | |
| #if 0 /* Not implemented (yet?) for Console */
 | |
| 
 | |
| static
 | |
| int
 | |
| EFIAPI
 | |
| da_ConCntl(
 | |
|   struct __filedes *filp,
 | |
|   UINT32,
 | |
|   void *,
 | |
|   void *
 | |
|   )
 | |
| {
 | |
| }
 | |
| 
 | |
| static
 | |
| int
 | |
| EFIAPI
 | |
| da_ConFlush(
 | |
|   struct __filedes *filp
 | |
|   )
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| #endif  /* Not implemented for Console */
 |