\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) 2010 - 2012, 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
#include <unistd.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
static DeviceNode *ConNode[NUM_SPECIAL];\r
static ConInstance *ConInstanceList;\r
\r
-static wchar_t *ConReadBuf;\r
+static cIIO *IIO;\r
\r
/* Flags settable by Ioctl */\r
static BOOLEAN TtyCooked;\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 dest WCS buffer to receive the converted string.\r
- @param buf MBCS string to convert to WCS.\r
- @param n Number of BYTES contained in buf.\r
- @param Cs Pointer to the character state object for this stream\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
return i;\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
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
gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed\r
- return RETURN_SUCCESS;\r
+ return 0;\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
\r
/* Write a NULL terminated WCS to the EFI console.\r
\r
- @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if\r
- the string couldn't be displayed.\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 BYTES written. Because of MBCS, this may be more than number of characters.\r
+ @return The number of Characters written.\r
*/\r
static\r
ssize_t\r
EFI_STATUS Status;\r
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
ConInstance *Stream;\r
- ssize_t NumBytes;\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
// Everything is OK to do the write.\r
Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
\r
- // Convert string from MBCS to WCS and translate \n to \r\n.\r
- NumBytes = WideTtyCvt(gMD->UString, (const char *)Buffer, (ssize_t)BufferSize, &Stream->CharState);\r
- BufferSize = NumBytes;\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, gMD->UString);\r
- // Depending on status, update BufferSize and return\r
- if(RETURN_ERROR(Status)) {\r
- BufferSize = 0; // We don't really know how many characters made it out\r
+ Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);\r
}\r
- else {\r
- //BufferSize = NumBytes;\r
- Stream->NumWritten += NumBytes;\r
+\r
+ // Depending on status, update BufferSize and return\r
+ if(!RETURN_ERROR(Status)) {\r
+ //BufferSize = NumChar;\r
+ NumChar = BufferSize;\r
+ Stream->NumWritten += NumChar;\r
}\r
EFIerrno = Status; // Make error reason available to caller\r
- return BufferSize;\r
+ return NumChar;\r
}\r
\r
-/** Read characters from the console input device.\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
- @param[in,out] filp Pointer to file descriptor for this file.\r
- @param[in,out] offset Ignored.\r
+ @param[in,out] BufferSize Number of characters in Buffer.\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
- @return Number of bytes actually placed into Buffer.\r
-\r
- @todo Handle encodings other than ASCII-7 and UEFI.\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
{\r
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
ConInstance *Stream;\r
- wchar_t *OutPtr;\r
- EFI_INPUT_KEY Key;\r
- UINTN NumChar;\r
- UINTN Edex;\r
+ cIIO *Self;\r
+ EFI_INPUT_KEY Key = {0,0};\r
EFI_STATUS Status = RETURN_SUCCESS;\r
- UINTN i;\r
- char EchoBuff[MB_CUR_MAX + 1];\r
- int NumEcho;\r
+ UINTN Edex;\r
+ ssize_t NumRead;\r
+ int Flags;\r
+ wchar_t RetChar; // Default to No Data\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
- // Read only valid for stdin\r
- EFIerrno = RETURN_UNSUPPORTED;\r
- return -1;\r
+ NumRead = -1;\r
+ if(BufferSize < sizeof(wchar_t)) {\r
+ errno = EINVAL; // Buffer is too small to hold one character\r
}\r
- // It looks like things are OK for trying to read\r
- // We will accumulate *BufferSize characters or until we encounter\r
- // an "activation" character. Currently any control character.\r
+ else {\r
+ Self = (cIIO *)filp->devdata;\r
+ Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
- OutPtr = ConReadBuf;\r
- NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;\r
- i = 0;\r
- do {\r
+ Flags = filp->Oflags;\r
if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
+ // No data pending in the Un-get buffer. Get a char from the hardware.\r
+ if((Flags & O_NONBLOCK) == 0) {\r
+ // Read a byte in Blocking mode\r
Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
- if(Status != RETURN_SUCCESS) {\r
- break;\r
+ EFIerrno = Status;\r
+ if(Status != EFI_SUCCESS) {\r
+ errno = EINVAL;\r
}\r
+ else {\r
Status = Proto->ReadKeyStroke(Proto, &Key);\r
- if(Status != RETURN_SUCCESS) {\r
- break;\r
+ if(Status == EFI_SUCCESS) {\r
+ NumRead = 1; // Indicate that Key holds the data\r
+ }\r
+ else {\r
+ errno = EIO;\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ // Read a byte in Non-Blocking mode\r
+ Status = Proto->ReadKeyStroke(Proto, &Key);\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
}\r
}\r
else {\r
+ // Use the data in the Un-get buffer\r
Key.ScanCode = Stream->UnGetKey.ScanCode;\r
Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;\r
Stream->UnGetKey.ScanCode = SCAN_NULL;\r
Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
+ NumRead = 1; // Indicate that Key holds the data\r
}\r
- if(Key.ScanCode == SCAN_NULL) {\r
- NumEcho = 0;\r
- if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
- *OutPtr++ = CHAR_LINEFEED;\r
- NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);\r
- }\r
- else {\r
- *OutPtr++ = Key.UnicodeChar;\r
- NumEcho = wctomb(EchoBuff, Key.UnicodeChar);\r
+ // If we have data, prepare it for return.\r
+ if(NumRead == 1) {\r
+ RetChar = Key.UnicodeChar;\r
+ if((RetChar == 0) && ((Self->Termio.c_iflag & IGNSPEC) == 0)) {\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 = (Key.ScanCode == 0) ? 0 : 0xF900U - Key.ScanCode;\r
}\r
- ++i;\r
- EchoBuff[NumEcho] = 0; /* Terminate the Echo buffer */\r
- if(TtyEcho) {\r
- /* Echo the character just input */\r
- da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);\r
+ *((wchar_t *)Buffer) = RetChar;\r
}\r
}\r
- if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code\r
- break;\r
- }\r
- } while(i < NumChar);\r
-\r
- *OutPtr = L'\0'; // Terminate the input buffer\r
-\r
- /* Convert the input buffer and place in Buffer.\r
- If the fully converted input buffer won't fit, write what will and\r
- leave the rest in ConReadBuf with ConReadLeft indicating how many\r
- unconverted characters remain in ConReadBuf.\r
- */\r
- NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize); /* Re-use NumEcho to hold number of bytes in Buffer */\r
- /* More work needs to be done before locales other than C can be supported. */\r
-\r
- EFIerrno = Status;\r
- return (ssize_t)NumEcho; // Will be 0 if we didn't get a key\r
+ return NumRead;\r
}\r
\r
/** Console-specific helper function for the fstat() function.\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
if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'\r
(Buffer == NULL))\r
{\r
+ errno = EINVAL;\r
EFIerrno = RETURN_INVALID_PARAMETER;\r
return -1;\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
va_list argp\r
)\r
{\r
- return -EPERM;\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
)\r
{\r
ConInstance *Stream;\r
+ UINT32 Instance;\r
+ int RetVal = -1;\r
\r
- if((filp == NULL) ||\r
- (DevNode == NULL))\r
+ if((filp != NULL) &&\r
+ (DevNode != NULL))\r
{\r
- EFIerrno = RETURN_INVALID_PARAMETER;\r
- errno = EINVAL;\r
- return -1;\r
- }\r
Stream = (ConInstance *)DevNode->InstanceList;\r
// Quick check to see if Stream looks reasonable\r
- if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\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
- return -1; // Looks like a bad This pointer\r
}\r
- gMD->StdIo[Stream->InstanceNum] = Stream;\r
- filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);\r
- filp->f_offset = 0;\r
- filp->f_ops = &Stream->Abstraction;\r
+ return RetVal;\r
\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
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
)\r
{\r
ConInstance *Stream;\r
- RETURN_STATUS Status = RETURN_SUCCESS;\r
+ RETURN_STATUS Status;\r
int i;\r
\r
+ Status = RETURN_OUT_OF_RESOURCES;\r
ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
- ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));\r
- if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {\r
- return RETURN_OUT_OF_RESOURCES;\r
+ if(ConInstanceList != NULL) {\r
+ IIO = New_cIIO();\r
+ if(IIO == NULL) {\r
+ FreePool(ConInstanceList);\r
}\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
if(Stream->Dev == NULL) {\r
continue; // No device for this stream.\r
}\r
- ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);\r
+ ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,\r
+ 1, sizeof(ConInstance), stdioFlags[i]);\r
if(ConNode[i] == NULL) {\r
- Status = EFIerrno;\r
+ Status = EFIerrno; // Grab error code that DevRegister produced.\r
break;\r
}\r
Stream->Parent = ConNode[i];\r
/* Initialize Ioctl flags until Ioctl is really implemented. */\r
TtyCooked = TRUE;\r
TtyEcho = TRUE;\r
-\r
+ }\r
+ }\r
return Status;\r
}\r
\r
if(ConInstanceList != NULL) {\r
FreePool(ConInstanceList);\r
}\r
- if(ConReadBuf != NULL) {\r
- FreePool(ConReadBuf);\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 for Console */\r
+#if 0 /* Not implemented (yet?) for Console */\r
\r
static\r
int\r