static DeviceNode *ConNode[NUM_SPECIAL];\r
static ConInstance *ConInstanceList;\r
\r
+static wchar_t *ConReadBuf;\r
+\r
+/* Flags settable by Ioctl */\r
+static BOOLEAN TtyCooked;\r
+static BOOLEAN TtyEcho;\r
+\r
ssize_t\r
WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)\r
{\r
}\r
}\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
- CHAR16 *OutPtr;\r
- EFI_INPUT_KEY Key;\r
- UINTN NumChar;\r
- UINTN Edex;\r
- EFI_STATUS Status = RETURN_SUCCESS;\r
- UINTN i;\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
- }\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
- Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
- OutPtr = Buffer;\r
- NumChar = (BufferSize - 1) / sizeof(CHAR16);\r
- i = 0;\r
- do {\r
- if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
- Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
- if(Status != RETURN_SUCCESS) {\r
- break;\r
- }\r
- Status = Proto->ReadKeyStroke(Proto, &Key);\r
- if(Status != RETURN_SUCCESS) {\r
- break;\r
- }\r
- }\r
- else {\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
- }\r
- if(Key.ScanCode == SCAN_NULL) {\r
- *OutPtr++ = Key.UnicodeChar;\r
- ++i;\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
- EFIerrno = Status;\r
- return (ssize_t)(i * sizeof(CHAR16)); // Will be 0 if we didn't get a key\r
-}\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
return BufferSize;\r
}\r
\r
+/** Read characters from the console input device.\r
+\r
+ @param[in,out] filp Pointer to file descriptor for this file.\r
+ @param[in,out] 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
+**/\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
+ wchar_t *OutPtr;\r
+ EFI_INPUT_KEY Key;\r
+ UINTN NumChar;\r
+ UINTN Edex;\r
+ EFI_STATUS Status = RETURN_SUCCESS;\r
+ UINTN i;\r
+ char EchoBuff[MB_CUR_MAX + 1];\r
+ int NumEcho;\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
+ }\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
+ 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
+ if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
+ Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
+ if(Status != RETURN_SUCCESS) {\r
+ break;\r
+ }\r
+ Status = Proto->ReadKeyStroke(Proto, &Key);\r
+ if(Status != RETURN_SUCCESS) {\r
+ break;\r
+ }\r
+ }\r
+ else {\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
+ }\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
+ }\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
+ }\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
+}\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
int\r
EFIAPI\r
da_ConOpen(\r
+ DeviceNode *DevNode,\r
struct __filedes *filp,\r
- void *DevInstance,\r
+ int DevInstance, // Not used for console devices\r
wchar_t *Path, // Not used for console devices\r
- wchar_t *Flags // Not used for console devices\r
+ wchar_t *MPath // Not used for console devices\r
)\r
{\r
ConInstance *Stream;\r
\r
if((filp == NULL) ||\r
- (DevInstance == NULL))\r
+ (DevNode == NULL))\r
{\r
EFIerrno = RETURN_INVALID_PARAMETER;\r
return -1;\r
}\r
- Stream = (ConInstance *)DevInstance;\r
+ Stream = (ConInstance *)DevNode->InstanceList;\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
- gMD->StdIo[Stream->InstanceNum] = (ConInstance *)DevInstance;\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
int i;\r
\r
ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
- if(ConInstanceList == NULL) {\r
+ ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));\r
+ if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {\r
return RETURN_OUT_OF_RESOURCES;\r
}\r
\r
}\r
Stream->Parent = ConNode[i];\r
}\r
+ /* Initialize Ioctl flags until Ioctl is really implemented. */\r
+ TtyCooked = TRUE;\r
+ TtyEcho = TRUE;\r
+\r
return Status;\r
}\r
\r
if(ConInstanceList != NULL) {\r
FreePool(ConInstanceList);\r
}\r
+ if(ConReadBuf != NULL) {\r
+ FreePool(ConReadBuf);\r
+ }\r
\r
return RETURN_SUCCESS;\r
}\r