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