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