summaryrefslogtreecommitdiff
path: root/StdLib/LibC/Uefi/Devices/Console/daConsole.c
diff options
context:
space:
mode:
Diffstat (limited to 'StdLib/LibC/Uefi/Devices/Console/daConsole.c')
-rw-r--r--StdLib/LibC/Uefi/Devices/Console/daConsole.c316
1 files changed, 205 insertions, 111 deletions
diff --git a/StdLib/LibC/Uefi/Devices/Console/daConsole.c b/StdLib/LibC/Uefi/Devices/Console/daConsole.c
index 4897a2e56e..927ec944ea 100644
--- a/StdLib/LibC/Uefi/Devices/Console/daConsole.c
+++ b/StdLib/LibC/Uefi/Devices/Console/daConsole.c
@@ -3,6 +3,13 @@
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 - 2012, 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.
@@ -30,6 +37,7 @@
#include <unistd.h>
#include <kfile.h>
#include <Device/Device.h>
+#include <Device/IIO.h>
#include <MainData.h>
static const CHAR16* const
@@ -46,7 +54,7 @@ static const int stdioFlags[NUM_SPECIAL] = {
static DeviceNode *ConNode[NUM_SPECIAL];
static ConInstance *ConInstanceList;
-static wchar_t *ConReadBuf;
+static cIIO *IIO;
/* Flags settable by Ioctl */
static BOOLEAN TtyCooked;
@@ -58,10 +66,10 @@ static BOOLEAN TtyEcho;
large enough to hold the converted results. It is guaranteed
that there will be fewer than n characters placed in dest.
- @param dest WCS buffer to receive the converted string.
- @param buf MBCS string to convert to WCS.
- @param n Number of BYTES contained in buf.
- @param Cs Pointer to the character state object for this stream
+ @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.
**/
@@ -94,6 +102,13 @@ WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)
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
@@ -106,13 +121,25 @@ da_ConClose(
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 RETURN_SUCCESS;
+ 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
@@ -155,11 +182,14 @@ da_ConSeek(
/* Write a NULL terminated WCS to the EFI console.
- @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if
- the string couldn't be displayed.
+ 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 BYTES written. Because of MBCS, this may be more than number of characters.
+ @return The number of Characters written.
*/
static
ssize_t
@@ -174,8 +204,10 @@ da_ConWrite(
EFI_STATUS Status;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
ConInstance *Stream;
- ssize_t NumBytes;
+ 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'
@@ -190,35 +222,45 @@ da_ConWrite(
// Everything is OK to do the write.
Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
- // Convert string from MBCS to WCS and translate \n to \r\n.
- NumBytes = WideTtyCvt(gMD->UString, (const char *)Buffer, (ssize_t)BufferSize, &Stream->CharState);
- BufferSize = NumBytes;
+ 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, gMD->UString);
- // Depending on status, update BufferSize and return
- if(RETURN_ERROR(Status)) {
- BufferSize = 0; // We don't really know how many characters made it out
+ Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);
}
- else {
- //BufferSize = NumBytes;
- Stream->NumWritten += NumBytes;
+
+ // Depending on status, update BufferSize and return
+ if(!RETURN_ERROR(Status)) {
+ //BufferSize = NumChar;
+ NumChar = BufferSize;
+ Stream->NumWritten += NumChar;
}
EFIerrno = Status; // Make error reason available to caller
- return BufferSize;
+ return NumChar;
}
-/** Read characters from the console input device.
+/** 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.
- @param[in,out] filp Pointer to file descriptor for this file.
- @param[in,out] offset Ignored.
+ @param[in,out] BufferSize Number of characters in Buffer.
+ @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.
- @return Number of bytes actually placed into Buffer.
-
- @todo Handle encodings other than ASCII-7 and UEFI.
+ @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
@@ -232,84 +274,80 @@ da_ConRead(
{
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
ConInstance *Stream;
- wchar_t *OutPtr;
- EFI_INPUT_KEY Key;
- UINTN NumChar;
- UINTN Edex;
+ cIIO *Self;
+ EFI_INPUT_KEY Key = {0,0};
EFI_STATUS Status = RETURN_SUCCESS;
- UINTN i;
- char EchoBuff[MB_CUR_MAX + 1];
- int NumEcho;
+ UINTN Edex;
+ ssize_t NumRead;
+ int Flags;
+ wchar_t RetChar; // Default to No Data
- 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) {
- // Read only valid for stdin
- EFIerrno = RETURN_UNSUPPORTED;
- return -1;
+ NumRead = -1;
+ if(BufferSize < sizeof(wchar_t)) {
+ errno = EINVAL; // Buffer is too small to hold one character
}
- // It looks like things are OK for trying to read
- // We will accumulate *BufferSize characters or until we encounter
- // an "activation" character. Currently any control character.
+ else {
+ Self = (cIIO *)filp->devdata;
+ Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
- OutPtr = ConReadBuf;
- NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;
- i = 0;
- do {
+ Flags = filp->Oflags;
if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
+ // No data pending in the Un-get buffer. Get a char from the hardware.
+ if((Flags & O_NONBLOCK) == 0) {
+ // Read a byte in Blocking mode
Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
- if(Status != RETURN_SUCCESS) {
- break;
+ EFIerrno = Status;
+ if(Status != EFI_SUCCESS) {
+ errno = EINVAL;
}
+ else {
Status = Proto->ReadKeyStroke(Proto, &Key);
- if(Status != RETURN_SUCCESS) {
- break;
+ if(Status == EFI_SUCCESS) {
+ NumRead = 1; // Indicate that Key holds the data
+ }
+ else {
+ errno = EIO;
+ }
+ }
+ }
+ else {
+ // Read a byte in Non-Blocking mode
+ Status = Proto->ReadKeyStroke(Proto, &Key);
+ 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;
+ }
}
}
else {
+ // Use the data in the Un-get buffer
Key.ScanCode = Stream->UnGetKey.ScanCode;
Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;
Stream->UnGetKey.ScanCode = SCAN_NULL;
Stream->UnGetKey.UnicodeChar = CHAR_NULL;
+ NumRead = 1; // Indicate that Key holds the data
}
- if(Key.ScanCode == SCAN_NULL) {
- NumEcho = 0;
- if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
- *OutPtr++ = CHAR_LINEFEED;
- NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);
- }
- else {
- *OutPtr++ = Key.UnicodeChar;
- NumEcho = wctomb(EchoBuff, Key.UnicodeChar);
+ // If we have data, prepare it for return.
+ if(NumRead == 1) {
+ RetChar = Key.UnicodeChar;
+ if((RetChar == 0) && ((Self->Termio.c_iflag & IGNSPEC) == 0)) {
+ // Must be a control, function, or other non-printable key.
+ // Map it into the Platform portion of the Unicode private use area
+ RetChar = (Key.ScanCode == 0) ? 0 : 0xF900U - Key.ScanCode;
}
- ++i;
- EchoBuff[NumEcho] = 0; /* Terminate the Echo buffer */
- if(TtyEcho) {
- /* Echo the character just input */
- da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);
+ *((wchar_t *)Buffer) = RetChar;
}
}
- if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code
- break;
- }
- } while(i < NumChar);
-
- *OutPtr = L'\0'; // Terminate the input buffer
-
- /* Convert the input buffer and place in Buffer.
- If the fully converted input buffer won't fit, write what will and
- leave the rest in ConReadBuf with ConReadLeft indicating how many
- unconverted characters remain in ConReadBuf.
- */
- NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize); /* Re-use NumEcho to hold number of bytes in Buffer */
- /* More work needs to be done before locales other than C can be supported. */
-
- EFIerrno = Status;
- return (ssize_t)NumEcho; // Will be 0 if we didn't get a key
+ return NumRead;
}
/** Console-specific helper function for the fstat() function.
@@ -320,6 +358,14 @@ da_ConRead(
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
@@ -343,6 +389,7 @@ da_ConStat(
if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'
(Buffer == NULL))
{
+ errno = EINVAL;
EFIerrno = RETURN_INVALID_PARAMETER;
return -1;
}
@@ -378,6 +425,14 @@ da_ConStat(
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
@@ -387,10 +442,21 @@ da_ConIoctl(
va_list argp
)
{
- return -EPERM;
+ 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
@@ -403,36 +469,57 @@ da_ConOpen(
)
{
ConInstance *Stream;
+ UINT32 Instance;
+ int RetVal = -1;
- if((filp == NULL) ||
- (DevNode == NULL))
+ if((filp != NULL) &&
+ (DevNode != NULL))
{
- EFIerrno = RETURN_INVALID_PARAMETER;
- errno = EINVAL;
- return -1;
- }
Stream = (ConInstance *)DevNode->InstanceList;
// Quick check to see if Stream looks reasonable
- if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
+ 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 -1; // Looks like a bad This pointer
}
- gMD->StdIo[Stream->InstanceNum] = Stream;
- filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);
- filp->f_offset = 0;
- filp->f_ops = &Stream->Abstraction;
+ return RetVal;
- return 0;
}
#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
@@ -450,6 +537,7 @@ da_ConPoll(
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
}
@@ -495,15 +583,18 @@ __Cons_construct(
)
{
ConInstance *Stream;
- RETURN_STATUS Status = RETURN_SUCCESS;
+ RETURN_STATUS Status;
int i;
+ Status = RETURN_OUT_OF_RESOURCES;
ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));
- ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));
- if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {
- return RETURN_OUT_OF_RESOURCES;
+ 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];
@@ -553,9 +644,10 @@ __Cons_construct(
if(Stream->Dev == NULL) {
continue; // No device for this stream.
}
- ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);
+ ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,
+ 1, sizeof(ConInstance), stdioFlags[i]);
if(ConNode[i] == NULL) {
- Status = EFIerrno;
+ Status = EFIerrno; // Grab error code that DevRegister produced.
break;
}
Stream->Parent = ConNode[i];
@@ -563,7 +655,8 @@ __Cons_construct(
/* Initialize Ioctl flags until Ioctl is really implemented. */
TtyCooked = TRUE;
TtyEcho = TRUE;
-
+ }
+ }
return Status;
}
@@ -584,15 +677,16 @@ __Cons_deconstruct(
if(ConInstanceList != NULL) {
FreePool(ConInstanceList);
}
- if(ConReadBuf != NULL) {
- FreePool(ConReadBuf);
+ if(IIO != NULL) {
+ IIO->Delete(IIO);
+ IIO = NULL;
}
return RETURN_SUCCESS;
}
/* ######################################################################### */
-#if 0 /* Not implemented for Console */
+#if 0 /* Not implemented (yet?) for Console */
static
int