]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/Devices/Console/daConsole.c
StdLib: Some deployed versions of the Simple Text Input Protocol randomly return...
[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
364 BlockingMode = ((filp->Oflags & O_NONBLOCK) == 0);\r
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
589 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
590 ConInstance *Stream;\r
591 EFI_STATUS Status = RETURN_SUCCESS;\r
592 short RdyMask = 0;\r
593\r
594 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
595 // Quick check to see if Stream looks reasonable\r
596 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
6c6c850a 597 errno = EINVAL;\r
53e1e5c6 598 EFIerrno = RETURN_INVALID_PARAMETER;\r
599 return POLLNVAL; // Looks like a bad filp pointer\r
600 }\r
601 if(Stream->InstanceNum == 0) {\r
24903bc4 602 // STDIN: Only input is supported for this device\r
53e1e5c6 603 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
24903bc4
DM
604 Status = da_ConRawRead (filp, &Stream->UnGetKey);\r
605 if(Status == RETURN_SUCCESS) {\r
606 RdyMask = POLLIN;\r
607 if ((Stream->UnGetKey < TtyFunKeyMin) ||\r
608 (Stream->UnGetKey >= TtyFunKeyMax))\r
609 {\r
610 RdyMask |= POLLRDNORM;\r
53e1e5c6 611 }\r
612 }\r
24903bc4
DM
613 else {\r
614 Stream->UnGetKey = CHAR_NULL;\r
615 }\r
53e1e5c6 616 }\r
617 else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2?\r
24903bc4 618 // (STDOUT || STDERR): Only output is supported for this device\r
53e1e5c6 619 RdyMask = POLLOUT;\r
620 }\r
621 else {\r
622 RdyMask = POLLERR; // Not one of the standard streams\r
623 }\r
624 EFIerrno = Status;\r
625\r
626 return (RdyMask & (events | POLL_RETONLY));\r
627}\r
628\r
629/** Construct the Console stream devices: stdin, stdout, stderr.\r
630\r
631 Allocate the instance structure and populate it with the information for\r
632 each stream device.\r
633**/\r
634RETURN_STATUS\r
635EFIAPI\r
636__Cons_construct(\r
637 IN EFI_HANDLE ImageHandle,\r
638 IN EFI_SYSTEM_TABLE *SystemTable\r
639)\r
640{\r
641 ConInstance *Stream;\r
6c6c850a 642 RETURN_STATUS Status;\r
53e1e5c6 643 int i;\r
644\r
6c6c850a 645 Status = RETURN_OUT_OF_RESOURCES;\r
53e1e5c6 646 ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
6c6c850a 647 if(ConInstanceList != NULL) {\r
648 IIO = New_cIIO();\r
649 if(IIO == NULL) {\r
650 FreePool(ConInstanceList);\r
53e1e5c6 651 }\r
6c6c850a 652 else {\r
653 Status = RETURN_SUCCESS;\r
53e1e5c6 654 for( i = 0; i < NUM_SPECIAL; ++i) {\r
655 // Get pointer to instance.\r
656 Stream = &ConInstanceList[i];\r
657\r
658 Stream->Cookie = CON_COOKIE;\r
659 Stream->InstanceNum = i;\r
a7a8363d 660 Stream->CharState.A = 0; // Start in the initial state\r
53e1e5c6 661\r
662 switch(i) {\r
663 case STDIN_FILENO:\r
664 Stream->Dev = SystemTable->ConIn;\r
665 break;\r
666 case STDOUT_FILENO:\r
667 Stream->Dev = SystemTable->ConOut;\r
668 break;\r
669 case STDERR_FILENO:\r
670 if(SystemTable->StdErr == NULL) {\r
671 Stream->Dev = SystemTable->ConOut;\r
672 }\r
673 else {\r
674 Stream->Dev = SystemTable->StdErr;\r
675 }\r
676 break;\r
677 default:\r
678 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.\r
679 }\r
680\r
681 Stream->Abstraction.fo_close = &da_ConClose;\r
682 Stream->Abstraction.fo_read = &da_ConRead;\r
683 Stream->Abstraction.fo_write = &da_ConWrite;\r
684 Stream->Abstraction.fo_stat = &da_ConStat;\r
685 Stream->Abstraction.fo_lseek = &da_ConSeek;\r
686 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;\r
687 Stream->Abstraction.fo_ioctl = &da_ConIoctl;\r
688 Stream->Abstraction.fo_poll = &da_ConPoll;\r
689 Stream->Abstraction.fo_flush = &fnullop_flush;\r
690 Stream->Abstraction.fo_delete = &fbadop_delete;\r
691 Stream->Abstraction.fo_mkdir = &fbadop_mkdir;\r
692 Stream->Abstraction.fo_rmdir = &fbadop_rmdir;\r
693 Stream->Abstraction.fo_rename = &fbadop_rename;\r
694\r
695 Stream->NumRead = 0;\r
696 Stream->NumWritten = 0;\r
24903bc4 697 Stream->UnGetKey = CHAR_NULL;\r
53e1e5c6 698\r
699 if(Stream->Dev == NULL) {\r
700 continue; // No device for this stream.\r
701 }\r
6c6c850a 702 ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream,\r
703 1, sizeof(ConInstance), stdioFlags[i]);\r
53e1e5c6 704 if(ConNode[i] == NULL) {\r
6c6c850a 705 Status = EFIerrno; // Grab error code that DevRegister produced.\r
53e1e5c6 706 break;\r
707 }\r
708 Stream->Parent = ConNode[i];\r
709 }\r
d7ce7006 710 /* Initialize Ioctl flags until Ioctl is really implemented. */\r
711 TtyCooked = TRUE;\r
712 TtyEcho = TRUE;\r
6c6c850a 713 }\r
714 }\r
53e1e5c6 715 return Status;\r
716}\r
717\r
718RETURN_STATUS\r
719EFIAPI\r
720__Cons_deconstruct(\r
721 IN EFI_HANDLE ImageHandle,\r
722 IN EFI_SYSTEM_TABLE *SystemTable\r
723)\r
724{\r
725 int i;\r
726\r
727 for(i = 0; i < NUM_SPECIAL; ++i) {\r
728 if(ConNode[i] != NULL) {\r
729 FreePool(ConNode[i]);\r
730 }\r
731 }\r
732 if(ConInstanceList != NULL) {\r
733 FreePool(ConInstanceList);\r
734 }\r
6c6c850a 735 if(IIO != NULL) {\r
736 IIO->Delete(IIO);\r
737 IIO = NULL;\r
d7ce7006 738 }\r
53e1e5c6 739\r
740 return RETURN_SUCCESS;\r
741}\r
742\r
743/* ######################################################################### */\r
6c6c850a 744#if 0 /* Not implemented (yet?) for Console */\r
53e1e5c6 745\r
746static\r
747int\r
748EFIAPI\r
749da_ConCntl(\r
750 struct __filedes *filp,\r
751 UINT32,\r
752 void *,\r
753 void *\r
754 )\r
755{\r
756}\r
757\r
758static\r
759int\r
760EFIAPI\r
761da_ConFlush(\r
762 struct __filedes *filp\r
763 )\r
764{\r
765 return 0;\r
766}\r
767#endif /* Not implemented for Console */\r