]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/Devices/Console/daConsole.c
StdLib/LibC/Uefi/Devices/Console/daConsole.c: Fix bug where unconvertable wide chara...
[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
a7a8363d 6 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
53e1e5c6 7 This program and the accompanying materials are licensed and made available under\r
8 the terms and conditions of the BSD License that accompanies this distribution.\r
9 The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16#include <Uefi.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Protocol/SimpleTextIn.h>\r
21#include <Protocol/SimpleTextOut.h>\r
22\r
23#include <LibConfig.h>\r
53e1e5c6 24\r
25#include <errno.h>\r
26#include <wctype.h>\r
27#include <wchar.h>\r
76beedc0 28#include <stdarg.h>\r
53e1e5c6 29#include <sys/fcntl.h>\r
0c1992fb 30#include <unistd.h>\r
53e1e5c6 31#include <kfile.h>\r
32#include <Device/Device.h>\r
33#include <MainData.h>\r
34\r
35static const CHAR16* const\r
36stdioNames[NUM_SPECIAL] = {\r
37 L"stdin:", L"stdout:", L"stderr:"\r
38};\r
39\r
40static const int stdioFlags[NUM_SPECIAL] = {\r
41 O_RDONLY, // stdin\r
42 O_WRONLY, // stdout\r
43 O_WRONLY // stderr\r
44};\r
45\r
46static DeviceNode *ConNode[NUM_SPECIAL];\r
47static ConInstance *ConInstanceList;\r
48\r
d7ce7006 49static wchar_t *ConReadBuf;\r
50\r
51/* Flags settable by Ioctl */\r
52static BOOLEAN TtyCooked;\r
53static BOOLEAN TtyEcho;\r
54\r
a7a8363d 55/** Convert string from MBCS to WCS and translate \n to \r\n.\r
56\r
57 It is the caller's responsibility to ensure that dest is\r
58 large enough to hold the converted results. It is guaranteed\r
59 that there will be fewer than n characters placed in dest.\r
60\r
61 @param dest WCS buffer to receive the converted string.\r
62 @param buf MBCS string to convert to WCS.\r
63 @param n Number of BYTES contained in buf.\r
64 @param Cs Pointer to the character state object for this stream\r
65\r
66 @return The number of BYTES consumed from buf.\r
67**/\r
53e1e5c6 68ssize_t\r
a7a8363d 69WideTtyCvt( CHAR16 *dest, const char *buf, ssize_t n, mbstate_t *Cs)\r
53e1e5c6 70{\r
a7a8363d 71 ssize_t i = 0;\r
72 int numB = 0;\r
73 wchar_t wc[2];\r
53e1e5c6 74\r
a7a8363d 75 while(n > 0) {\r
76 numB = (int)mbrtowc(wc, buf, MIN(MB_LEN_MAX,n), Cs);\r
77 if( numB == 0) {\r
53e1e5c6 78 break;\r
79 };\r
ad07c107 80 if(numB < 0) { // If an unconvertable character, replace it.\r
a7a8363d 81 wc[0] = BLOCKELEMENT_LIGHT_SHADE;\r
ad07c107 82 numB = 1;\r
53e1e5c6 83 }\r
a7a8363d 84 if(wc[0] == L'\n') {\r
53e1e5c6 85 *dest++ = L'\r';\r
a7a8363d 86 ++i;\r
53e1e5c6 87 }\r
a7a8363d 88 *dest++ = (CHAR16)wc[0];\r
89 i += numB;\r
90 n -= numB;\r
91 buf += numB;\r
53e1e5c6 92 }\r
93 *dest = 0;\r
a7a8363d 94 return i;\r
53e1e5c6 95}\r
96\r
97static\r
98int\r
99EFIAPI\r
100da_ConClose(\r
101 IN struct __filedes *filp\r
102)\r
103{\r
104 ConInstance *Stream;\r
105\r
106 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
107 // Quick check to see if Stream looks reasonable\r
108 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
109 EFIerrno = RETURN_INVALID_PARAMETER;\r
110 return -1; // Looks like a bad File Descriptor pointer\r
111 }\r
112 gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed\r
113 return RETURN_SUCCESS;\r
114}\r
115\r
116static\r
117off_t\r
118EFIAPI\r
119da_ConSeek(\r
120 struct __filedes *filp,\r
121 off_t Position,\r
122 int whence ///< Ignored by Console\r
123)\r
124{\r
125 ConInstance *Stream;\r
126 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
a7a8363d 127 XY_OFFSET CursorPos;\r
53e1e5c6 128\r
129 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
130 // Quick check to see if Stream looks reasonable\r
131 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
132 EFIerrno = RETURN_INVALID_PARAMETER;\r
133 return -1; // Looks like a bad This pointer\r
134 }\r
135 if(Stream->InstanceNum == STDIN_FILENO) {\r
136 // Seek is not valid for stdin\r
137 EFIerrno = RETURN_UNSUPPORTED;\r
138 return -1;\r
139 }\r
140 // Everything is OK to do the final verification and "seek".\r
141 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
142 CursorPos.Offset = Position;\r
143\r
144 EFIerrno = Proto->SetCursorPosition(Proto,\r
145 (INTN)CursorPos.XYpos.Column,\r
146 (INTN)CursorPos.XYpos.Row);\r
147\r
148 if(RETURN_ERROR(EFIerrno)) {\r
149 return -1;\r
150 }\r
151 else {\r
152 return Position;\r
153 }\r
154}\r
155\r
53e1e5c6 156/* Write a NULL terminated WCS to the EFI console.\r
157\r
158 @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if\r
159 the string couldn't be displayed.\r
160 @param[in] Buffer The WCS string to be displayed\r
161\r
a7a8363d 162 @return The number of BYTES written. Because of MBCS, this may be more than number of characters.\r
53e1e5c6 163*/\r
164static\r
165ssize_t\r
166EFIAPI\r
167da_ConWrite(\r
168 IN struct __filedes *filp,\r
169 IN off_t *Position,\r
170 IN size_t BufferSize,\r
171 IN const void *Buffer\r
172 )\r
173{\r
174 EFI_STATUS Status;\r
175 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
176 ConInstance *Stream;\r
a7a8363d 177 ssize_t NumBytes;\r
53e1e5c6 178\r
179 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
180 // Quick check to see if Stream looks reasonable\r
181 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
182 EFIerrno = RETURN_INVALID_PARAMETER;\r
183 return -1; // Looks like a bad This pointer\r
184 }\r
185 if(Stream->InstanceNum == STDIN_FILENO) {\r
186 // Write is not valid for stdin\r
187 EFIerrno = RETURN_UNSUPPORTED;\r
188 return -1;\r
189 }\r
190 // Everything is OK to do the write.\r
191 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
192\r
193 // Convert string from MBCS to WCS and translate \n to \r\n.\r
a7a8363d 194 NumBytes = WideTtyCvt(gMD->UString, (const char *)Buffer, (ssize_t)BufferSize, &Stream->CharState);\r
195 BufferSize = NumBytes;\r
196\r
53e1e5c6 197\r
198 // Send the Unicode buffer to the console\r
199 Status = Proto->OutputString( Proto, gMD->UString);\r
200 // Depending on status, update BufferSize and return\r
201 if(RETURN_ERROR(Status)) {\r
a7a8363d 202 BufferSize = 0; // We don't really know how many characters made it out\r
53e1e5c6 203 }\r
204 else {\r
a7a8363d 205 //BufferSize = NumBytes;\r
206 Stream->NumWritten += NumBytes;\r
53e1e5c6 207 }\r
a7a8363d 208 EFIerrno = Status; // Make error reason available to caller\r
53e1e5c6 209 return BufferSize;\r
210}\r
211\r
d7ce7006 212/** Read characters from the console input device.\r
213\r
214 @param[in,out] filp Pointer to file descriptor for this file.\r
215 @param[in,out] offset Ignored.\r
216 @param[in] BufferSize Buffer size, in bytes.\r
217 @param[out] Buffer Buffer in which to place the read characters.\r
218\r
219 @return Number of bytes actually placed into Buffer.\r
220\r
221 @todo Handle encodings other than ASCII-7 and UEFI.\r
222**/\r
223static\r
224ssize_t\r
225EFIAPI\r
226da_ConRead(\r
227 IN OUT struct __filedes *filp,\r
228 IN OUT off_t *offset, // Console ignores this\r
229 IN size_t BufferSize,\r
230 OUT VOID *Buffer\r
231)\r
232{\r
233 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
234 ConInstance *Stream;\r
235 wchar_t *OutPtr;\r
236 EFI_INPUT_KEY Key;\r
237 UINTN NumChar;\r
238 UINTN Edex;\r
239 EFI_STATUS Status = RETURN_SUCCESS;\r
240 UINTN i;\r
241 char EchoBuff[MB_CUR_MAX + 1];\r
242 int NumEcho;\r
243\r
244 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
245 // Quick check to see if Stream looks reasonable\r
246 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
247 EFIerrno = RETURN_INVALID_PARAMETER;\r
248 return -1; // Looks like a bad This pointer\r
249 }\r
250 if(Stream->InstanceNum != STDIN_FILENO) {\r
251 // Read only valid for stdin\r
252 EFIerrno = RETURN_UNSUPPORTED;\r
253 return -1;\r
254 }\r
255 // It looks like things are OK for trying to read\r
256 // We will accumulate *BufferSize characters or until we encounter\r
257 // an "activation" character. Currently any control character.\r
258 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
259 OutPtr = ConReadBuf;\r
260 NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;\r
261 i = 0;\r
262 do {\r
263 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
264 Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);\r
265 if(Status != RETURN_SUCCESS) {\r
266 break;\r
267 }\r
268 Status = Proto->ReadKeyStroke(Proto, &Key);\r
269 if(Status != RETURN_SUCCESS) {\r
270 break;\r
271 }\r
272 }\r
273 else {\r
274 Key.ScanCode = Stream->UnGetKey.ScanCode;\r
275 Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;\r
276 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
277 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
278 }\r
279 if(Key.ScanCode == SCAN_NULL) {\r
280 NumEcho = 0;\r
281 if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
282 *OutPtr++ = CHAR_LINEFEED;\r
283 NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);\r
284 }\r
285 else {\r
286 *OutPtr++ = Key.UnicodeChar;\r
287 NumEcho = wctomb(EchoBuff, Key.UnicodeChar);\r
288 }\r
289 ++i;\r
290 EchoBuff[NumEcho] = 0; /* Terminate the Echo buffer */\r
291 if(TtyEcho) {\r
292 /* Echo the character just input */\r
293 da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);\r
294 }\r
295 }\r
296 if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code\r
297 break;\r
298 }\r
299 } while(i < NumChar);\r
300\r
301 *OutPtr = L'\0'; // Terminate the input buffer\r
302\r
303 /* Convert the input buffer and place in Buffer.\r
304 If the fully converted input buffer won't fit, write what will and\r
305 leave the rest in ConReadBuf with ConReadLeft indicating how many\r
306 unconverted characters remain in ConReadBuf.\r
307 */\r
308 NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize); /* Re-use NumEcho to hold number of bytes in Buffer */\r
309 /* More work needs to be done before locales other than C can be supported. */\r
310\r
311 EFIerrno = Status;\r
312 return (ssize_t)NumEcho; // Will be 0 if we didn't get a key\r
313}\r
314\r
53e1e5c6 315/** Console-specific helper function for the fstat() function.\r
316\r
317 st_size Set to number of characters read for stdin and number written for stdout and stderr.\r
318 st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode.\r
319 st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr\r
320 st_blksize Set to 1 since this is a character device\r
321\r
322 All other members of the stat structure are left unchanged.\r
323**/\r
324static\r
325int\r
326EFIAPI\r
327da_ConStat(\r
328 struct __filedes *filp,\r
329 struct stat *Buffer,\r
330 void *Something\r
331 )\r
332{\r
333 ConInstance *Stream;\r
334 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;\r
31a272eb 335 XY_OFFSET CursorPos;\r
53e1e5c6 336 INT32 OutMode;\r
337 UINTN ModeCol;\r
338 UINTN ModeRow;\r
339\r
340// ConGetInfo\r
341 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
342 // Quick check to see if Stream looks reasonable\r
343 if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb'\r
344 (Buffer == NULL))\r
345 {\r
346 EFIerrno = RETURN_INVALID_PARAMETER;\r
347 return -1;\r
348 }\r
349 // All of our parameters are correct, so fill in the information.\r
a7a8363d 350 Buffer->st_blksize = 0; // Character device, not a block device\r
351 Buffer->st_mode = filp->f_iflags;\r
53e1e5c6 352\r
353// ConGetPosition\r
354 if(Stream->InstanceNum == STDIN_FILENO) {\r
355 // This is stdin\r
356 Buffer->st_curpos = 0;\r
357 Buffer->st_size = (off_t)Stream->NumRead;\r
358 Buffer->st_physsize = 1;\r
359 }\r
360 else {\r
361 Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;\r
362 CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;\r
363 CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;\r
364 Buffer->st_curpos = (off_t)CursorPos.Offset;\r
365 Buffer->st_size = (off_t)Stream->NumWritten;\r
366\r
367 OutMode = Proto->Mode->Mode;\r
368 EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow);\r
369 if(RETURN_ERROR(EFIerrno)) {\r
370 Buffer->st_physsize = 0;\r
371 }\r
372 else {\r
373 CursorPos.XYpos.Column = (UINT32)ModeCol;\r
374 CursorPos.XYpos.Row = (UINT32)ModeRow;\r
375 Buffer->st_physsize = (off_t)CursorPos.Offset;\r
376 }\r
377 }\r
378 return 0;\r
379}\r
380\r
381static\r
382int\r
383EFIAPI\r
384da_ConIoctl(\r
385 struct __filedes *filp,\r
386 ULONGN cmd,\r
76beedc0 387 va_list argp\r
53e1e5c6 388 )\r
389{\r
390 return -EPERM;\r
391}\r
392\r
393/** Open an abstract Console Device.\r
394**/\r
395int\r
396EFIAPI\r
397da_ConOpen(\r
d7ce7006 398 DeviceNode *DevNode,\r
53e1e5c6 399 struct __filedes *filp,\r
d7ce7006 400 int DevInstance, // Not used for console devices\r
53e1e5c6 401 wchar_t *Path, // Not used for console devices\r
d7ce7006 402 wchar_t *MPath // Not used for console devices\r
53e1e5c6 403 )\r
404{\r
405 ConInstance *Stream;\r
406\r
407 if((filp == NULL) ||\r
d7ce7006 408 (DevNode == NULL))\r
53e1e5c6 409 {\r
410 EFIerrno = RETURN_INVALID_PARAMETER;\r
8379337c 411 errno = EINVAL;\r
53e1e5c6 412 return -1;\r
413 }\r
d7ce7006 414 Stream = (ConInstance *)DevNode->InstanceList;\r
53e1e5c6 415 // Quick check to see if Stream looks reasonable\r
416 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
417 EFIerrno = RETURN_INVALID_PARAMETER;\r
8379337c 418 errno = EINVAL;\r
53e1e5c6 419 return -1; // Looks like a bad This pointer\r
420 }\r
d7ce7006 421 gMD->StdIo[Stream->InstanceNum] = Stream;\r
53e1e5c6 422 filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);\r
423 filp->f_offset = 0;\r
424 filp->f_ops = &Stream->Abstraction;\r
425\r
426 return 0;\r
427}\r
428\r
429#include <sys/poll.h>\r
430/* Returns a bit mask describing which operations could be completed immediately.\r
431\r
432 (POLLIN | POLLRDNORM) A Unicode character is available to read\r
433 (POLLIN) A ScanCode is ready.\r
434 (POLLOUT) The device is ready for output - always set on stdout and stderr.\r
435\r
436*/\r
437static\r
438short\r
439EFIAPI\r
440da_ConPoll(\r
441 struct __filedes *filp,\r
442 short events\r
443 )\r
444{\r
445 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;\r
446 ConInstance *Stream;\r
447 EFI_STATUS Status = RETURN_SUCCESS;\r
448 short RdyMask = 0;\r
449\r
450 Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);\r
451 // Quick check to see if Stream looks reasonable\r
452 if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'\r
453 EFIerrno = RETURN_INVALID_PARAMETER;\r
454 return POLLNVAL; // Looks like a bad filp pointer\r
455 }\r
456 if(Stream->InstanceNum == 0) {\r
457 // Only input is supported for this device\r
458 Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;\r
459 if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {\r
460 Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey);\r
461 if(Status == RETURN_SUCCESS) {\r
462 RdyMask = POLLIN;\r
463 if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) {\r
464 RdyMask |= POLLRDNORM;\r
465 }\r
466 }\r
467 else {\r
468 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
469 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
470 }\r
471 }\r
472 }\r
473 else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2?\r
474 // Only output is supported for this device\r
475 RdyMask = POLLOUT;\r
476 }\r
477 else {\r
478 RdyMask = POLLERR; // Not one of the standard streams\r
479 }\r
480 EFIerrno = Status;\r
481\r
482 return (RdyMask & (events | POLL_RETONLY));\r
483}\r
484\r
485/** Construct the Console stream devices: stdin, stdout, stderr.\r
486\r
487 Allocate the instance structure and populate it with the information for\r
488 each stream device.\r
489**/\r
490RETURN_STATUS\r
491EFIAPI\r
492__Cons_construct(\r
493 IN EFI_HANDLE ImageHandle,\r
494 IN EFI_SYSTEM_TABLE *SystemTable\r
495)\r
496{\r
497 ConInstance *Stream;\r
498 RETURN_STATUS Status = RETURN_SUCCESS;\r
499 int i;\r
500\r
501 ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));\r
d7ce7006 502 ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));\r
503 if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {\r
53e1e5c6 504 return RETURN_OUT_OF_RESOURCES;\r
505 }\r
506\r
507 for( i = 0; i < NUM_SPECIAL; ++i) {\r
508 // Get pointer to instance.\r
509 Stream = &ConInstanceList[i];\r
510\r
511 Stream->Cookie = CON_COOKIE;\r
512 Stream->InstanceNum = i;\r
a7a8363d 513 Stream->CharState.A = 0; // Start in the initial state\r
53e1e5c6 514\r
515 switch(i) {\r
516 case STDIN_FILENO:\r
517 Stream->Dev = SystemTable->ConIn;\r
518 break;\r
519 case STDOUT_FILENO:\r
520 Stream->Dev = SystemTable->ConOut;\r
521 break;\r
522 case STDERR_FILENO:\r
523 if(SystemTable->StdErr == NULL) {\r
524 Stream->Dev = SystemTable->ConOut;\r
525 }\r
526 else {\r
527 Stream->Dev = SystemTable->StdErr;\r
528 }\r
529 break;\r
530 default:\r
531 return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.\r
532 }\r
533\r
534 Stream->Abstraction.fo_close = &da_ConClose;\r
535 Stream->Abstraction.fo_read = &da_ConRead;\r
536 Stream->Abstraction.fo_write = &da_ConWrite;\r
537 Stream->Abstraction.fo_stat = &da_ConStat;\r
538 Stream->Abstraction.fo_lseek = &da_ConSeek;\r
539 Stream->Abstraction.fo_fcntl = &fnullop_fcntl;\r
540 Stream->Abstraction.fo_ioctl = &da_ConIoctl;\r
541 Stream->Abstraction.fo_poll = &da_ConPoll;\r
542 Stream->Abstraction.fo_flush = &fnullop_flush;\r
543 Stream->Abstraction.fo_delete = &fbadop_delete;\r
544 Stream->Abstraction.fo_mkdir = &fbadop_mkdir;\r
545 Stream->Abstraction.fo_rmdir = &fbadop_rmdir;\r
546 Stream->Abstraction.fo_rename = &fbadop_rename;\r
547\r
548 Stream->NumRead = 0;\r
549 Stream->NumWritten = 0;\r
550 Stream->UnGetKey.ScanCode = SCAN_NULL;\r
551 Stream->UnGetKey.UnicodeChar = CHAR_NULL;\r
552\r
553 if(Stream->Dev == NULL) {\r
554 continue; // No device for this stream.\r
555 }\r
556 ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]);\r
557 if(ConNode[i] == NULL) {\r
558 Status = EFIerrno;\r
559 break;\r
560 }\r
561 Stream->Parent = ConNode[i];\r
562 }\r
d7ce7006 563 /* Initialize Ioctl flags until Ioctl is really implemented. */\r
564 TtyCooked = TRUE;\r
565 TtyEcho = TRUE;\r
566\r
53e1e5c6 567 return Status;\r
568}\r
569\r
570RETURN_STATUS\r
571EFIAPI\r
572__Cons_deconstruct(\r
573 IN EFI_HANDLE ImageHandle,\r
574 IN EFI_SYSTEM_TABLE *SystemTable\r
575)\r
576{\r
577 int i;\r
578\r
579 for(i = 0; i < NUM_SPECIAL; ++i) {\r
580 if(ConNode[i] != NULL) {\r
581 FreePool(ConNode[i]);\r
582 }\r
583 }\r
584 if(ConInstanceList != NULL) {\r
585 FreePool(ConInstanceList);\r
586 }\r
d7ce7006 587 if(ConReadBuf != NULL) {\r
588 FreePool(ConReadBuf);\r
589 }\r
53e1e5c6 590\r
591 return RETURN_SUCCESS;\r
592}\r
593\r
594/* ######################################################################### */\r
595#if 0 /* Not implemented for Console */\r
596\r
597static\r
598int\r
599EFIAPI\r
600da_ConCntl(\r
601 struct __filedes *filp,\r
602 UINT32,\r
603 void *,\r
604 void *\r
605 )\r
606{\r
607}\r
608\r
609static\r
610int\r
611EFIAPI\r
612da_ConFlush(\r
613 struct __filedes *filp\r
614 )\r
615{\r
616 return 0;\r
617}\r
618#endif /* Not implemented for Console */\r