]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/Devices/Console/daConsole.c
StdLib: Fix compilation errors caused by previous commit of daConsole.c
[mirror_edk2.git] / StdLib / LibC / Uefi / Devices / Console / daConsole.c
CommitLineData
53e1e5c6 1/** @file\r
2 Abstract device driver for the UEFI Console.\r
3\r
4 Manipulates abstractions for stdin, stdout, stderr.\r
5\r
6c6c850a 6 This device is a WIDE device and this driver returns WIDE\r
7 characters. It this the responsibility of the caller to convert between\r
8 narrow and wide characters in order to perform the desired operations.\r
9\r
10 The devices status as a wide device is indicatd by _S_IWTTY being set in\r
11 f_iflags.\r
12\r
4e8f2b29 13 Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>\r
24903bc4 14 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
53e1e5c6 15 This program and the accompanying materials are licensed and made available under\r
16 the terms and conditions of the BSD License that accompanies this distribution.\r
17 The full text of the license may be found at\r
18 http://opensource.org/licenses/bsd-license.php.\r
19\r
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23**/\r
24#include <Uefi.h>\r
25#include <Library/BaseLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/UefiBootServicesTableLib.h>\r
24903bc4 28#include <Library/DebugLib.h>\r
53e1e5c6 29#include <Protocol/SimpleTextIn.h>\r
30#include <Protocol/SimpleTextOut.h>\r
31\r
32#include <LibConfig.h>\r
53e1e5c6 33\r
34#include <errno.h>\r
35#include <wctype.h>\r
36#include <wchar.h>\r
76beedc0 37#include <stdarg.h>\r
53e1e5c6 38#include <sys/fcntl.h>\r
0c1992fb 39#include <unistd.h>\r
24903bc4 40#include <sys/termios.h>\r
4e8f2b29 41#include <Efi/SysEfi.h>\r
53e1e5c6 42#include <kfile.h>\r
43#include <Device/Device.h>\r
6c6c850a 44#include <Device/IIO.h>\r
53e1e5c6 45#include <MainData.h>\r
46\r
47static const CHAR16* const\r
48stdioNames[NUM_SPECIAL] = {\r
49 L"stdin:", L"stdout:", L"stderr:"\r
50};\r
51\r
52static const int stdioFlags[NUM_SPECIAL] = {\r
53 O_RDONLY, // stdin\r
54 O_WRONLY, // stdout\r
55 O_WRONLY // stderr\r
56};\r
57\r
58static DeviceNode *ConNode[NUM_SPECIAL];\r
59static ConInstance *ConInstanceList;\r
60\r
6c6c850a 61static cIIO *IIO;\r
d7ce7006 62\r
63/* Flags settable by Ioctl */\r
64static BOOLEAN TtyCooked;\r
65static BOOLEAN TtyEcho;\r
66\r
a7a8363d 67/** Convert string from MBCS to WCS and translate \n to \r\n.\r
68\r
69 It is the caller's responsibility to ensure that dest is\r
70 large enough to hold the converted results. It is guaranteed\r
71 that there will be fewer than n characters placed in dest.\r
72\r
6c6c850a 73 @param[out] dest WCS buffer to receive the converted string.\r
74 @param[in] buf MBCS string to convert to WCS.\r
75 @param[in] n Number of BYTES contained in buf.\r
76 @param[in,out] Cs Pointer to the character state object for this stream\r
a7a8363d 77\r
78 @return The number of BYTES consumed from buf.\r
79**/\r
53e1e5c6 80ssize_t\r
a7a8363d 81WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)\r
53e1e5c6 82{\r
a7a8363d 83 ssize_t i = 0;\r
84 int numB = 0;\r
85 wchar_t wc[2];\r
53e1e5c6 86\r
a7a8363d 87 while(n > 0) {\r
88 numB = (int)mbrtowc(wc, buf, MIN(MB_LEN_MAX,n), Cs);\r
89 if( numB == 0) {\r
53e1e5c6 90 break;\r
91 };\r
ad07c107 92 if(numB < 0) { // If an unconvertable character, replace it.\r
a7a8363d 93 wc[0] = BLOCKELEMENT_LIGHT_SHADE;\r
ad07c107 94 numB = 1;\r
53e1e5c6 95 }\r
a7a8363d 96 if(wc[0] == L'\n') {\r
53e1e5c6 97 *dest++ = L'\r';\r
a7a8363d 98 ++i;\r
53e1e5c6 99 }\r
a7a8363d 100 *dest++ = (CHAR16)wc[0];\r
101 i += numB;\r
102 n -= numB;\r
103 buf += numB;\r
53e1e5c6 104 }\r
105 *dest = 0;\r
a7a8363d 106 return i;\r
53e1e5c6 107}\r
108\r
6c6c850a 109/** Position the console cursor to the coordinates specified by Position.\r
110\r
111 @param[in] filp Pointer to the file descriptor structure for this file.\r
112 @param[in] Position A value containing the target X and Y coordinates.\r
113 @param[in] whence Ignored by the Console device.\r
114\r
115 @retval Position Success. Returns a copy of the Position argument.\r
116 @retval -1 filp is not associated with a valid console stream.\r
117 @retval -1 This console stream is attached to stdin.\r
118 @retval -1 The SetCursorPosition operation failed.\r
119**/\r
53e1e5c6 120static\r
121off_t\r
122EFIAPI\r
123da_ConSeek(\r
124 struct __filedes *filp,\r
125 off_t Position,\r
126 int whence ///< Ignored by Console\r
127)\r
128{\r
129 ConInstance *Stream;\r
130 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
a7a8363d 131 XY_OFFSET CursorPos;\r
53e1e5c6 132\r
133 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
134 // Quick check to see if Stream looks reasonable\r
135 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
136 EFIerrno = RETURN_INVALID_PARAMETER;\r
137 return -1; // Looks like a bad This pointer\r
138 }\r
139 if(Stream->InstanceNum == STDIN_FILENO) {\r
140 // Seek is not valid for stdin\r
141 EFIerrno = RETURN_UNSUPPORTED;\r
142 return -1;\r
143 }\r
144 // Everything is OK to do the final verification and "seek".\r
145 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
146 CursorPos.Offset = Position;\r
147\r
148 EFIerrno = Proto->SetCursorPosition(Proto,\r
149 (INTN)CursorPos.XYpos.Column,\r
150 (INTN)CursorPos.XYpos.Row);\r
151\r
152 if(RETURN_ERROR(EFIerrno)) {\r
153 return -1;\r
154 }\r
155 else {\r
156 return Position;\r
157 }\r
158}\r
159\r
53e1e5c6 160/* Write a NULL terminated WCS to the EFI console.\r
161\r
6c6c850a 162 NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters received\r
163 by da_ConWrite are WIDE characters. It is the responsibility of the\r
164 higher-level function(s) to perform any necessary conversions.\r
165\r
4e8f2b29 166 @param[in,out] BufferSize Number of characters in Buffer.\r
53e1e5c6 167 @param[in] Buffer The WCS string to be displayed\r
168\r
4e8f2b29 169 @return The number of Characters written.\r
53e1e5c6 170*/\r
171static\r
172ssize_t\r
173EFIAPI\r
174da_ConWrite(\r
175 IN struct __filedes *filp,\r
176 IN off_t *Position,\r
177 IN size_t BufferSize,\r
178 IN const void *Buffer\r
179 )\r
180{\r
181 EFI_STATUS Status;\r
182 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
183 ConInstance *Stream;\r
6c6c850a 184 ssize_t NumChar;\r
185 XY_OFFSET CursorPos;\r
53e1e5c6 186\r
6c6c850a 187 NumChar = -1;\r
53e1e5c6 188 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
189 // Quick check to see if Stream looks reasonable\r
190 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
191 EFIerrno = RETURN_INVALID_PARAMETER;\r
192 return -1; // Looks like a bad This pointer\r
193 }\r
194 if(Stream->InstanceNum == STDIN_FILENO) {\r
195 // Write is not valid for stdin\r
196 EFIerrno = RETURN_UNSUPPORTED;\r
197 return -1;\r
198 }\r
199 // Everything is OK to do the write.\r
200 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
201\r
6c6c850a 202 Status = EFI_SUCCESS;\r
203 if(Position != NULL) {\r
204 CursorPos.Offset = *Position;\r
a7a8363d 205\r
6c6c850a 206 Status = Proto->SetCursorPosition(Proto,\r
207 (INTN)CursorPos.XYpos.Column,\r
208 (INTN)CursorPos.XYpos.Row);\r
53e1e5c6 209\r
6c6c850a 210 }\r
211 if(!RETURN_ERROR(Status)) {\r
53e1e5c6 212 // Send the Unicode buffer to the console\r
6c6c850a 213 Status = Proto->OutputString( Proto, (CHAR16 *)Buffer);\r
53e1e5c6 214 }\r
6c6c850a 215\r
216 // Depending on status, update BufferSize and return\r
217 if(!RETURN_ERROR(Status)) {\r
6c6c850a 218 NumChar = BufferSize;\r
219 Stream->NumWritten += NumChar;\r
53e1e5c6 220 }\r
a7a8363d 221 EFIerrno = Status; // Make error reason available to caller\r
6c6c850a 222 return NumChar;\r
53e1e5c6 223}\r
224\r
24903bc4
DM
225/** Read a wide character from the console input device.\r
226\r
227 Returns NUL or a translated input character.\r
228\r
229 @param[in] filp Pointer to file descriptor for this file.\r
230 @param[out] Buffer Buffer in which to place the read character.\r
231\r
232 @retval EFI_DEVICE_ERROR A hardware error has occurred.\r
233 @retval EFI_NOT_READY No data is available. Try again later.\r
234 @retval EFI_SUCCESS One wide character has been placed in Character\r
235 - 0x0000 NUL, ignore this\r
236 - Otherwise, should be a good wide character in Character\r
237**/\r
238static\r
239EFI_STATUS\r
240da_ConRawRead (\r
241 IN OUT struct __filedes *filp,\r
242 OUT wchar_t *Character\r
243)\r
244{\r
245 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
246 ConInstance *Stream;\r
247 cIIO *Self;\r
248 EFI_STATUS Status;\r
249 EFI_INPUT_KEY Key = {0,0};\r
250 wchar_t RetChar;\r
251\r
252 Self = (cIIO *)filp->devdata;\r
253 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
254 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
255\r
256 if(Stream->UnGetKey == CHAR_NULL) {\r
257 Status = Proto->ReadKeyStroke(Proto, &Key);\r
258 }\r
259 else {\r
260 Status = EFI_SUCCESS;\r
261 // Use the data in the Un-get buffer\r
262 // Guaranteed that ScanCode and UnicodeChar are not both NUL\r
263 Key.ScanCode = SCAN_NULL;\r
264 Key.UnicodeChar = Stream->UnGetKey;\r
265 Stream->UnGetKey = CHAR_NULL;\r
266 }\r
267 if(Status == EFI_SUCCESS) {\r
268 // Translate the Escape Scan Code to an ESC character\r
269 if (Key.ScanCode != 0) {\r
270 if (Key.ScanCode == SCAN_ESC) {\r
271 RetChar = CHAR_ESC;\r
272 }\r
273 else if((Self->Termio.c_iflag & IGNSPEC) != 0) {\r
274 // If we are ignoring special characters, return a NUL\r
275 RetChar = 0;\r
276 }\r
277 else {\r
278 // Must be a control, function, or other non-printable key.\r
279 // Map it into the Platform portion of the Unicode private use area\r
280 RetChar = TtyFunKeyMax - Key.ScanCode;\r
281 }\r
282 }\r
283 else {\r
284 RetChar = Key.UnicodeChar;\r
285 }\r
286 *Character = RetChar;\r
287 }\r
288 else {\r
289 *Character = 0;\r
290 }\r
291 return Status;\r
292}\r
293\r
6c6c850a 294/** Read a wide character from the console input device.\r
295\r
296 NOTE: The UEFI Console is a wide device, _S_IWTTY, so characters returned\r
297 by da_ConRead are WIDE characters. It is the responsibility of the\r
298 higher-level function(s) to perform any necessary conversions.\r
d7ce7006 299\r
24903bc4
DM
300 A NUL character, 0x0000, is never returned. In the event that such a character\r
301 is encountered, the read is either retried or -1 is returned with errno set\r
302 to EAGAIN.\r
303\r
6c6c850a 304 @param[in] filp Pointer to file descriptor for this file.\r
305 @param[in] offset Ignored.\r
d7ce7006 306 @param[in] BufferSize Buffer size, in bytes.\r
307 @param[out] Buffer Buffer in which to place the read characters.\r
308\r
6c6c850a 309 @retval -1 An error has occurred. Reason in errno and EFIerrno.\r
310 @retval -1 No data is available. errno is set to EAGAIN\r
311 @retval 1 One wide character has been placed in Buffer\r
d7ce7006 312**/\r
313static\r
314ssize_t\r
315EFIAPI\r
316da_ConRead(\r
317 IN OUT struct __filedes *filp,\r
318 IN OUT off_t *offset, // Console ignores this\r
319 IN size_t BufferSize,\r
320 OUT VOID *Buffer\r
321)\r
322{\r
323 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
324 ConInstance *Stream;\r
24903bc4
DM
325 //cIIO *Self;\r
326 EFI_STATUS Status;\r
6c6c850a 327 UINTN Edex;\r
328 ssize_t NumRead;\r
24903bc4
DM
329 BOOLEAN BlockingMode;\r
330 wchar_t RetChar;\r
d7ce7006 331\r
6c6c850a 332 NumRead = -1;\r
333 if(BufferSize < sizeof(wchar_t)) {\r
334 errno = EINVAL; // Buffer is too small to hold one character\r
d7ce7006 335 }\r
6c6c850a 336 else {\r
24903bc4
DM
337 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
338 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
4b2cf923 339 BlockingMode = (BOOLEAN)((filp->Oflags & O_NONBLOCK) == 0);\r
24903bc4
DM
340\r
341 do {\r
342 Status = EFI_SUCCESS;\r
343 if(BlockingMode) {\r
6c6c850a 344 // Read a byte in Blocking mode\r
24903bc4 345 Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
d7ce7006 346 }\r
24903bc4
DM
347\r
348 /* WaitForEvent should not be able to fail since\r
349 NumberOfEvents is set to constant 1 so is never 0\r
350 Event is set by the Simple Text Input protocol so should never be EVT_NOTIFY_SIGNAL\r
351 Current TPL should be TPL_APPLICATION.\r
352 ASSERT so that we catch any problems during development.\r
353 */\r
354 ASSERT(Status == EFI_SUCCESS);\r
355\r
356 Status = da_ConRawRead (filp, &RetChar);\r
357 } while ( BlockingMode &&\r
358 (RetChar == 0) &&\r
359 (Status != EFI_DEVICE_ERROR));\r
360\r
361 EFIerrno = Status;\r
362 if(Status == EFI_SUCCESS) {\r
363 // Got a keystroke.\r
364 NumRead = 1; // Indicate that Key holds the data\r
365 }\r
366 else if(Status == EFI_NOT_READY) {\r
367 // Keystroke data is not available\r
368 errno = EAGAIN;\r
d7ce7006 369 }\r
370 else {\r
24903bc4
DM
371 // Hardware error\r
372 errno = EIO;\r
d7ce7006 373 }\r
24903bc4
DM
374 if (RetChar == 0) {\r
375 NumRead = -1;\r
376 errno = EAGAIN;\r
377 }\r
378 else {\r
6c6c850a 379 *((wchar_t *)Buffer) = RetChar;\r
d7ce7006 380 }\r
24903bc4 381 }\r
6c6c850a 382 return NumRead;\r
d7ce7006 383}\r
384\r
53e1e5c6 385/** Console-specific helper function for the fstat() function.\r
386\r
387 st_size Set to number of characters read for stdin and number written for stdout and stderr.\r
388 st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode.\r
389 st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr\r
390 st_blksize Set to 1 since this is a character device\r
391\r
392 All other members of the stat structure are left unchanged.\r
6c6c850a 393\r
394 @param[in] filp Pointer to file descriptor for this file.\r
395 @param[out] Buffer Pointer to a stat structure to receive the information.\r
396 @param[in,out] Something Ignored.\r
397\r
398 @retval 0 Successful completion.\r
399 @retval -1 Either filp is not associated with a console stream, or\r
400 Buffer is NULL. errno is set to EINVAL.\r
53e1e5c6 401**/\r
402static\r
403int\r
404EFIAPI\r
405da_ConStat(\r
406 struct __filedes *filp,\r
407 struct stat *Buffer,\r
408 void *Something\r
409 )\r
410{\r
411 ConInstance *Stream;\r
412 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
31a272eb 413 XY_OFFSET CursorPos;\r
53e1e5c6 414 INT32 OutMode;\r
415 UINTN ModeCol;\r
416 UINTN ModeRow;\r
417\r
418// ConGetInfo\r
419 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
420 // Quick check to see if Stream looks reasonable\r
421 if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'\r
422 (Buffer == NULL))\r
423 {\r
6c6c850a 424 errno = EINVAL;\r
53e1e5c6 425 EFIerrno = RETURN_INVALID_PARAMETER;\r
426 return -1;\r
427 }\r
428 // All of our parameters are correct, so fill in the information.\r
a7a8363d 429 Buffer->st_blksize = 0; // Character device, not a block device\r
430 Buffer->st_mode = filp->f_iflags;\r
53e1e5c6 431\r
432// ConGetPosition\r
433 if(Stream->InstanceNum == STDIN_FILENO) {\r
434 // This is stdin\r
435 Buffer->st_curpos = 0;\r
436 Buffer->st_size = (off_t)Stream->NumRead;\r
437 Buffer->st_physsize = 1;\r
438 }\r
439 else {\r
440 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
441 CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;\r
442 CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;\r
443 Buffer->st_curpos = (off_t)CursorPos.Offset;\r
444 Buffer->st_size = (off_t)Stream->NumWritten;\r
445\r
446 OutMode = Proto->Mode->Mode;\r
447 EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);\r
448 if(RETURN_ERROR(EFIerrno)) {\r
449 Buffer->st_physsize = 0;\r
450 }\r
451 else {\r
452 CursorPos.XYpos.Column = (UINT32)ModeCol;\r
453 CursorPos.XYpos.Row = (UINT32)ModeRow;\r
454 Buffer->st_physsize = (off_t)CursorPos.Offset;\r
455 }\r
456 }\r
457 return 0;\r
458}\r
459\r
6c6c850a 460/** Console-specific helper for the ioctl system call.\r
461\r
462 The console device does not directly participate in ioctl operations.\r
463 This function completes the device abstraction and returns an error value\r
464 to indicate that the function is not supported for this device.\r
465\r
466 @retval -1 Function is not supported for this device.\r
467**/\r
53e1e5c6 468static\r
469int\r
470EFIAPI\r
471da_ConIoctl(\r
472 struct __filedes *filp,\r
473 ULONGN cmd,\r
76beedc0 474 va_list argp\r
53e1e5c6 475 )\r
476{\r
6c6c850a 477 errno = ENODEV;\r
478 return -1;\r
53e1e5c6 479}\r
480\r
481/** Open an abstract Console Device.\r
6c6c850a 482\r
483 @param[in] DevNode Pointer to the Device control structure for this stream.\r
484 @param[in] filp Pointer to the new file control structure for this stream.\r
485 @param[in] DevInstance Not used for the console device.\r
486 @param[in] Path Not used for the console device.\r
487 @param[in] MPath Not used for the console device.\r
488\r
489 @retval 0 This console stream has been successfully opened.\r
490 @retval -1 The DevNode or filp pointer is NULL.\r
491 @retval -1 DevNode does not point to a valid console stream device.\r
53e1e5c6 492**/\r
493int\r
494EFIAPI\r
495da_ConOpen(\r
d7ce7006 496 DeviceNode *DevNode,\r
53e1e5c6 497 struct __filedes *filp,\r
d7ce7006 498 int DevInstance, // Not used for console devices\r
53e1e5c6 499 wchar_t *Path, // Not used for console devices\r
d7ce7006 500 wchar_t *MPath // Not used for console devices\r
53e1e5c6 501 )\r
502{\r
4e8f2b29 503 ConInstance *Stream;\r
6c6c850a 504 UINT32 Instance;\r
505 int RetVal = -1;\r
53e1e5c6 506\r
6c6c850a 507 if((filp != NULL) &&\r
508 (DevNode != NULL))\r
53e1e5c6 509 {\r
d7ce7006 510 Stream = (ConInstance *)DevNode->InstanceList;\r
53e1e5c6 511 // Quick check to see if Stream looks reasonable\r
6c6c850a 512 if(Stream->Cookie == CON_COOKIE)\r
513 {\r
514 Instance = Stream->InstanceNum;\r
515 if(Instance < NUM_SPECIAL) {\r
516 gMD->StdIo[Instance] = Stream;\r
517 filp->f_iflags |= (_S_IFCHR | _S_ITTY | _S_IWTTY | _S_ICONSOLE);\r
518 filp->f_offset = 0;\r
519 filp->f_ops = &Stream->Abstraction;\r
520 filp->devdata = (void *)IIO;\r
521 RetVal = 0;\r
522 }\r
523 }\r
524 }\r
525 if (RetVal < 0) {\r
53e1e5c6 526 EFIerrno = RETURN_INVALID_PARAMETER;\r
8379337c 527 errno = EINVAL;\r
53e1e5c6 528 }\r
6c6c850a 529 return RetVal;\r
53e1e5c6 530\r
53e1e5c6 531}\r
532\r
c96bf1ff
DM
533/** Flush a console device's IIO buffers.\r
534\r
535 Flush the IIO Input or Output buffers associated with the specified file.\r
536\r
537 If the console is open for output, write any unwritten data in the associated\r
538 output buffer (stdout or stderr) to the console.\r
539\r
540 If the console is open for input, discard any remaining data\r
541 in the input buffer.\r
542\r
543 @param[in] filp Pointer to the target file's descriptor structure.\r
544\r
545 @retval 0 Always succeeds\r
546**/\r
547static\r
548int\r
549EFIAPI\r
550da_ConFlush(\r
551 struct __filedes *filp\r
552)\r
553{\r
554 cFIFO *OutBuf;\r
555 ssize_t NumProc;\r
556 int Flags;\r
557\r
558\r
559 if(filp->MyFD == STDERR_FILENO) {\r
560 OutBuf = IIO->ErrBuf;\r
561 }\r
562 else {\r
563 OutBuf = IIO->OutBuf;\r
564 }\r
565\r
566 Flags = filp->Oflags & O_ACCMODE; // Get the device's open mode\r
567 if (Flags != O_WRONLY) { // (Flags == O_RDONLY) || (Flags == O_RDWR)\r
568 // Readable so discard the contents of the input buffer\r
569 IIO->InBuf->Flush(IIO->InBuf, UNICODE_STRING_MAX);\r
570 }\r
571 if (Flags != O_RDONLY) { // (Flags == O_WRONLY) || (Flags == O_RDWR)\r
572 // Writable so flush the output buffer\r
573 // At this point, the characters to write are in OutBuf\r
574 // First, linearize and consume the buffer\r
575 NumProc = OutBuf->Read(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
576 if (NumProc > 0) { // Optimization -- Nothing to do if no characters\r
577 gMD->UString[NumProc] = 0; // Ensure that the buffer is terminated\r
578\r
579 /* OutBuf always contains wide characters.\r
580 The UEFI Console (this device) always expects wide characters.\r
581 There is no need to handle devices that expect narrow characters\r
582 like the device-independent functions do.\r
583 */\r
584 // Do the actual write of the data to the console\r
585 (void) da_ConWrite(filp, NULL, NumProc, gMD->UString);\r
586 // Paranoia -- Make absolutely sure that OutBuf is empty in case fo_write\r
587 // wasn't able to consume everything.\r
588 OutBuf->Flush(OutBuf, UNICODE_STRING_MAX);\r
589 }\r
590 }\r
591 return 0;\r
592}\r
593\r
594/** Close an open file.\r
595\r
596 @param[in] filp Pointer to the file descriptor structure for this file.\r
597\r
598 @retval 0 The file has been successfully closed.\r
599 @retval -1 filp does not point to a valid console descriptor.\r
600**/\r
601static\r
602int\r
603EFIAPI\r
604da_ConClose(\r
605 IN struct __filedes *filp\r
606)\r
607{\r
608 ConInstance *Stream;\r
609\r
610 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
611 // Quick check to see if Stream looks reasonable\r
612 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
613 errno = EINVAL;\r
614 EFIerrno = RETURN_INVALID_PARAMETER;\r
615 return -1; // Looks like a bad File Descriptor pointer\r
616 }\r
617 // Stream and filp look OK, so continue.\r
618 // Flush the I/O buffers\r
619 (void) da_ConFlush(filp);\r
620\r
621 // Break the connection to IIO\r
622 filp->devdata = NULL;\r
623\r
624 gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed\r
625 return 0;\r
626}\r
627\r
53e1e5c6 628#include <sys/poll.h>\r
629/* Returns a bit mask describing which operations could be completed immediately.\r
630\r
6c6c850a 631 Testable Events for this device are:\r
53e1e5c6 632 (POLLIN | POLLRDNORM) A Unicode character is available to read\r
633 (POLLIN) A ScanCode is ready.\r
634 (POLLOUT) The device is ready for output - always set on stdout and stderr.\r
635\r
6c6c850a 636 Non-testable Events which are only valid in return values are:\r
637 POLLERR The specified device is not one of stdin, stdout, or stderr.\r
638 POLLHUP The specified stream has been disconnected\r
639 POLLNVAL da_ConPoll was called with an invalid parameter.\r
640\r
641 NOTE: The "Events" handled by this function are not UEFI events.\r
642\r
643 @param[in] filp Pointer to the file control structure for this stream.\r
644 @param[in] events A bit mask identifying the events to be examined\r
645 for this device.\r
646\r
647 @return Returns a bit mask comprised of both testable and non-testable\r
648 event codes indicating both the state of the operation and the\r
649 status of the device.\r
53e1e5c6 650*/\r
651static\r
652short\r
653EFIAPI\r
654da_ConPoll(\r
655 struct __filedes *filp,\r
656 short events\r
657 )\r
658{\r
53e1e5c6 659 ConInstance *Stream;\r
660 EFI_STATUS Status = RETURN_SUCCESS;\r
661 short RdyMask = 0;\r
662\r
663 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
664 // Quick check to see if Stream looks reasonable\r
665 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
6c6c850a 666 errno = EINVAL;\r
53e1e5c6 667 EFIerrno = RETURN_INVALID_PARAMETER;\r
668 return POLLNVAL; // Looks like a bad filp pointer\r
669 }\r
670 if(Stream->InstanceNum == 0) {\r
24903bc4 671 // STDIN: Only input is supported for this device\r
24903bc4
DM
672 Status = da_ConRawRead (filp, &Stream->UnGetKey);\r
673 if(Status == RETURN_SUCCESS) {\r
674 RdyMask = POLLIN;\r
675 if ((Stream->UnGetKey < TtyFunKeyMin) ||\r
676 (Stream->UnGetKey >= TtyFunKeyMax))\r
677 {\r
678 RdyMask |= POLLRDNORM;\r
53e1e5c6 679 }\r
680 }\r
24903bc4
DM
681 else {\r
682 Stream->UnGetKey = CHAR_NULL;\r
683 }\r
53e1e5c6 684 }\r
685 else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2?\r
24903bc4 686 // (STDOUT || STDERR): Only output is supported for this device\r
53e1e5c6 687 RdyMask = POLLOUT;\r
688 }\r
689 else {\r
690 RdyMask = POLLERR; // Not one of the standard streams\r
691 }\r
692 EFIerrno = Status;\r
693\r
694 return (RdyMask & (events | POLL_RETONLY));\r
695}\r
696\r
697/** Construct the Console stream devices: stdin, stdout, stderr.\r
698\r
699 Allocate the instance structure and populate it with the information for\r
700 each stream device.\r
701**/\r
702RETURN_STATUS\r
703EFIAPI\r
704__Cons_construct(\r
705 IN EFI_HANDLE ImageHandle,\r
706 IN EFI_SYSTEM_TABLE *SystemTable\r
707)\r
708{\r
709 ConInstance *Stream;\r
6c6c850a 710 RETURN_STATUS Status;\r
53e1e5c6 711 int i;\r
712\r
6c6c850a 713 Status = RETURN_OUT_OF_RESOURCES;\r
53e1e5c6 714 ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
6c6c850a 715 if(ConInstanceList != NULL) {\r
716 IIO = New_cIIO();\r
717 if(IIO == NULL) {\r
718 FreePool(ConInstanceList);\r
4e8f2b29 719 }\r
6c6c850a 720 else {\r
721 Status = RETURN_SUCCESS;\r
4e8f2b29
DM
722 for( i = 0; i < NUM_SPECIAL; ++i) {\r
723 // Get pointer to instance.\r
724 Stream = &ConInstanceList[i];\r
725\r
726 Stream->Cookie = CON_COOKIE;\r
727 Stream->InstanceNum = i;\r
728 Stream->CharState.A = 0; // Start in the initial state\r
729\r
730 switch(i) {\r
731 case STDIN_FILENO:\r
732 Stream->Dev = SystemTable->ConIn;\r
733 break;\r
734 case STDOUT_FILENO:\r
735 Stream->Dev = SystemTable->ConOut;\r
736 break;\r
737 case STDERR_FILENO:\r
738 if(SystemTable->StdErr == NULL) {\r
739 Stream->Dev = SystemTable->ConOut;\r
740 }\r
741 else {\r
742 Stream->Dev = SystemTable->StdErr;\r
743 }\r
744 break;\r
745 default:\r
746 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.\r
53e1e5c6 747 }\r
53e1e5c6 748\r
4e8f2b29
DM
749 Stream->Abstraction.fo_close = &da_ConClose;\r
750 Stream->Abstraction.fo_read = &da_ConRead;\r
751 Stream->Abstraction.fo_write = &da_ConWrite;\r
752 Stream->Abstraction.fo_stat = &da_ConStat;\r
753 Stream->Abstraction.fo_lseek = &da_ConSeek;\r
754 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;\r
755 Stream->Abstraction.fo_ioctl = &da_ConIoctl;\r
756 Stream->Abstraction.fo_poll = &da_ConPoll;\r
757 Stream->Abstraction.fo_flush = &da_ConFlush;\r
758 Stream->Abstraction.fo_delete = &fbadop_delete;\r
759 Stream->Abstraction.fo_mkdir = &fbadop_mkdir;\r
760 Stream->Abstraction.fo_rmdir = &fbadop_rmdir;\r
761 Stream->Abstraction.fo_rename = &fbadop_rename;\r
762\r
763 Stream->NumRead = 0;\r
764 Stream->NumWritten = 0;\r
765 Stream->UnGetKey = CHAR_NULL;\r
766\r
767 if(Stream->Dev == NULL) {\r
768 continue; // No device for this stream.\r
769 }\r
770 ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,\r
771 1, sizeof(ConInstance), stdioFlags[i]);\r
772 if(ConNode[i] == NULL) {\r
773 Status = EFIerrno; // Grab error code that DevRegister produced.\r
774 break;\r
775 }\r
776 Stream->Parent = ConNode[i];\r
777 }\r
778 /* Initialize Ioctl flags until Ioctl is really implemented. */\r
779 TtyCooked = TRUE;\r
780 TtyEcho = TRUE;\r
6c6c850a 781 }\r
782 }\r
53e1e5c6 783 return Status;\r
784}\r
785\r
786RETURN_STATUS\r
787EFIAPI\r
788__Cons_deconstruct(\r
789 IN EFI_HANDLE ImageHandle,\r
790 IN EFI_SYSTEM_TABLE *SystemTable\r
791)\r
792{\r
793 int i;\r
794\r
795 for(i = 0; i < NUM_SPECIAL; ++i) {\r
796 if(ConNode[i] != NULL) {\r
797 FreePool(ConNode[i]);\r
798 }\r
799 }\r
800 if(ConInstanceList != NULL) {\r
801 FreePool(ConInstanceList);\r
802 }\r
6c6c850a 803 if(IIO != NULL) {\r
804 IIO->Delete(IIO);\r
805 IIO = NULL;\r
d7ce7006 806 }\r
53e1e5c6 807\r
808 return RETURN_SUCCESS;\r
809}\r
810\r
811/* ######################################################################### */\r
6c6c850a 812#if 0 /* Not implemented (yet?) for Console */\r
53e1e5c6 813\r
814static\r
815int\r
816EFIAPI\r
817da_ConCntl(\r
818 struct __filedes *filp,\r
819 UINT32,\r
820 void *,\r
821 void *\r
822 )\r
823{\r
824}\r
53e1e5c6 825#endif /* Not implemented for Console */\r