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