]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
Fix NT32 Keyboard driver to call hotkey callback even no one is calling ReadKeyStroke().
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
CommitLineData
fb0b259e 1/** @file\r
11baadb6 2 Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and\r
fb0b259e 3 Simple Text Output Protocol upon Serial IO Protocol.\r
95276127 4\r
e5eed7d3
HT
5Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
95276127 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
fb0b259e 14**/\r
95276127 15\r
16\r
95276127 17#include "Terminal.h"\r
18\r
95276127 19//\r
20// Globals\r
21//\r
22EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {\r
23 TerminalDriverBindingSupported,\r
24 TerminalDriverBindingStart,\r
25 TerminalDriverBindingStop,\r
26 0xa,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
31\r
6b88ceec
A
32EFI_GUID *gTerminalType[] = {\r
33 &gEfiPcAnsiGuid,\r
34 &gEfiVT100Guid,\r
35 &gEfiVT100PlusGuid,\r
36 &gEfiVTUTF8Guid\r
37};\r
38\r
39\r
204ba917 40TERMINAL_DEV mTerminalDevTemplate = {\r
6b88ceec
A
41 TERMINAL_DEV_SIGNATURE,\r
42 NULL,\r
43 0,\r
44 NULL,\r
45 NULL,\r
46 { // SimpleTextInput\r
47 TerminalConInReset,\r
48 TerminalConInReadKeyStroke,\r
49 NULL\r
50 },\r
51 { // SimpleTextOutput\r
52 TerminalConOutReset,\r
53 TerminalConOutOutputString,\r
54 TerminalConOutTestString,\r
55 TerminalConOutQueryMode,\r
56 TerminalConOutSetMode,\r
57 TerminalConOutSetAttribute,\r
58 TerminalConOutClearScreen,\r
59 TerminalConOutSetCursorPosition,\r
60 TerminalConOutEnableCursor,\r
61 NULL\r
62 },\r
63 { // SimpleTextOutputMode\r
64 1, // MaxMode\r
11baadb6 65 0, // Mode\r
6b88ceec
A
66 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK), // Attribute\r
67 0, // CursorColumn\r
68 0, // CursorRow\r
69 TRUE // CursorVisible\r
70 },\r
11baadb6 71 0, // SerialInTimeOut\r
5c998646 72\r
73 NULL, // RawFifo\r
74 NULL, // UnicodeFiFo\r
75 NULL, // EfiKeyFiFo\r
76\r
6b88ceec 77 NULL, // ControllerNameTable\r
11baadb6 78 NULL, // TwoSecondTimeOut\r
6b88ceec
A
79 INPUT_STATE_DEFAULT,\r
80 RESET_STATE_DEFAULT,\r
66aa04e4 81 FALSE,\r
82 { // SimpleTextInputEx\r
83 TerminalConInResetEx,\r
84 TerminalConInReadKeyStrokeEx,\r
85 NULL,\r
86 TerminalConInSetState,\r
87 TerminalConInRegisterKeyNotify,\r
88 TerminalConInUnregisterKeyNotify,\r
89 },\r
11baadb6 90 { // NotifyList\r
66aa04e4 91 NULL,\r
92 NULL,\r
93 }\r
6b88ceec
A
94};\r
95\r
8fd98315 96/**\r
677fdb90 97 Test to see if this driver supports Controller.\r
8fd98315 98\r
99 @param This Protocol instance pointer.\r
ab76200c 100 @param Controller Handle of device to test\r
8fd98315 101 @param RemainingDevicePath Optional parameter use to pick a specific child\r
102 device to start.\r
103\r
ab76200c 104 @retval EFI_SUCCESS This driver supports this device.\r
105 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
106 @retval other This driver does not support this device.\r
6b88ceec 107\r
8fd98315 108**/\r
95276127 109EFI_STATUS\r
110EFIAPI\r
111TerminalDriverBindingSupported (\r
112 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
113 IN EFI_HANDLE Controller,\r
114 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
115 )\r
116{\r
117 EFI_STATUS Status;\r
118 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
119 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
120 VENDOR_DEVICE_PATH *Node;\r
121\r
122 //\r
123 // If remaining device path is not NULL, then make sure it is a\r
124 // device path that describes a terminal communications protocol.\r
125 //\r
126 if (RemainingDevicePath != NULL) {\r
95276127 127 //\r
e3dcffcc 128 // Check if RemainingDevicePath is the End of Device Path Node,\r
af4a6385 129 // if yes, go on checking other conditions\r
95276127 130 //\r
af4a6385 131 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
132 //\r
133 // If RemainingDevicePath isn't the End of Device Path Node,\r
134 // check its validation\r
135 //\r
136 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
e3dcffcc 137\r
af4a6385 138 if (Node->Header.Type != MESSAGING_DEVICE_PATH ||\r
139 Node->Header.SubType != MSG_VENDOR_DP ||\r
140 DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {\r
e3dcffcc 141\r
af4a6385 142 return EFI_UNSUPPORTED;\r
e3dcffcc 143\r
af4a6385 144 }\r
145 //\r
146 // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types\r
147 //\r
148 if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&\r
149 !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&\r
150 !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&\r
151 !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
e3dcffcc 152\r
af4a6385 153 return EFI_UNSUPPORTED;\r
154 }\r
95276127 155 }\r
156 }\r
157 //\r
158 // Open the IO Abstraction(s) needed to perform the supported test\r
af4a6385 159 // The Controller must support the Serial I/O Protocol.\r
160 // This driver is a bus driver with at most 1 child device, so it is\r
161 // ok for it to be already started.\r
95276127 162 //\r
163 Status = gBS->OpenProtocol (\r
164 Controller,\r
af4a6385 165 &gEfiSerialIoProtocolGuid,\r
166 (VOID **) &SerialIo,\r
95276127 167 This->DriverBindingHandle,\r
168 Controller,\r
169 EFI_OPEN_PROTOCOL_BY_DRIVER\r
170 );\r
171 if (Status == EFI_ALREADY_STARTED) {\r
172 return EFI_SUCCESS;\r
173 }\r
174\r
175 if (EFI_ERROR (Status)) {\r
176 return Status;\r
177 }\r
178\r
af4a6385 179 //\r
180 // Close the I/O Abstraction(s) used to perform the supported test\r
181 //\r
95276127 182 gBS->CloseProtocol (\r
183 Controller,\r
af4a6385 184 &gEfiSerialIoProtocolGuid,\r
95276127 185 This->DriverBindingHandle,\r
186 Controller\r
187 );\r
188\r
189 //\r
af4a6385 190 // Open the EFI Device Path protocol needed to perform the supported test\r
95276127 191 //\r
192 Status = gBS->OpenProtocol (\r
193 Controller,\r
af4a6385 194 &gEfiDevicePathProtocolGuid,\r
195 (VOID **) &ParentDevicePath,\r
95276127 196 This->DriverBindingHandle,\r
197 Controller,\r
198 EFI_OPEN_PROTOCOL_BY_DRIVER\r
199 );\r
200 if (Status == EFI_ALREADY_STARTED) {\r
201 return EFI_SUCCESS;\r
202 }\r
203\r
204 if (EFI_ERROR (Status)) {\r
205 return Status;\r
206 }\r
af4a6385 207\r
95276127 208 //\r
af4a6385 209 // Close protocol, don't use device path protocol in the Support() function\r
95276127 210 //\r
211 gBS->CloseProtocol (\r
212 Controller,\r
af4a6385 213 &gEfiDevicePathProtocolGuid,\r
95276127 214 This->DriverBindingHandle,\r
215 Controller\r
216 );\r
217\r
218 return Status;\r
219}\r
220\r
e3dcffcc 221/**\r
222 Build the terminal device path for the child device according to the\r
223 terminal type.\r
224\r
225 @param ParentDevicePath Parent device path.\r
226 @param RemainingDevicePath A specific child device.\r
227\r
228 @return The child device path built.\r
229\r
230**/\r
231EFI_DEVICE_PATH_PROTOCOL*\r
232EFIAPI\r
233BuildTerminalDevpath (\r
234 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
235 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
236 )\r
237{\r
238 EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;\r
239 UINT8 TerminalType;\r
240 VENDOR_DEVICE_PATH *Node;\r
241 EFI_STATUS Status;\r
242\r
243 TerminalDevicePath = NULL;\r
244 TerminalType = PCANSITYPE;\r
245\r
246 //\r
247 // Use the RemainingDevicePath to determine the terminal type\r
248 //\r
249 Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
250 if (Node == NULL) {\r
251 TerminalType = PCANSITYPE;\r
252\r
253 } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
254\r
255 TerminalType = PCANSITYPE;\r
256\r
257 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
258\r
259 TerminalType = VT100TYPE;\r
260\r
261 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
262\r
263 TerminalType = VT100PLUSTYPE;\r
264\r
265 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
266\r
267 TerminalType = VTUTF8TYPE;\r
268\r
269 } else {\r
270 return NULL;\r
271 }\r
272\r
273 //\r
274 // Build the device path for the child device\r
275 //\r
276 Status = SetTerminalDevicePath (\r
277 TerminalType,\r
278 ParentDevicePath,\r
279 &TerminalDevicePath\r
280 );\r
281 if (EFI_ERROR (Status)) {\r
282 return NULL;\r
283 }\r
284 return TerminalDevicePath;\r
285}\r
286\r
287/**\r
288 Compare a device path data structure to that of all the nodes of a\r
289 second device path instance.\r
290\r
291 @param Multi A pointer to a multi-instance device path data structure.\r
292 @param Single A pointer to a single-instance device path data structure.\r
293\r
294 @retval TRUE If the Single is contained within Multi.\r
295 @retval FALSE The Single is not match within Multi.\r
296\r
297**/\r
298BOOLEAN\r
299MatchDevicePaths (\r
300 IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
301 IN EFI_DEVICE_PATH_PROTOCOL *Single\r
302 )\r
303{\r
304 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
305 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
306 UINTN Size;\r
307\r
308 DevicePath = Multi;\r
309 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
310 //\r
311 // Search for the match of 'Single' in 'Multi'\r
312 //\r
313 while (DevicePathInst != NULL) {\r
314 //\r
315 // If the single device path is found in multiple device paths,\r
316 // return success\r
317 //\r
318 if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
319 FreePool (DevicePathInst);\r
320 return TRUE;\r
321 }\r
322\r
323 FreePool (DevicePathInst);\r
324 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
325 }\r
326\r
327 return FALSE;\r
328}\r
329\r
330/**\r
331 Check whether the terminal device path is in the global variable.\r
332\r
333 @param VariableName Pointer to one global variable.\r
334 @param TerminalDevicePath Pointer to the terminal device's device path.\r
335\r
336 @retval TRUE The devcie is in the global variable.\r
337 @retval FALSE The devcie is not in the global variable.\r
338\r
339**/\r
340BOOLEAN\r
341IsTerminalInConsoleVariable (\r
342 IN CHAR16 *VariableName,\r
343 IN EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath\r
344 )\r
345{\r
346 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
347 BOOLEAN ReturnFlag;\r
348\r
349 //\r
350 // Get global variable and its size according to the name given.\r
351 //\r
352 Variable = GetEfiGlobalVariable (VariableName);\r
353 if (Variable == NULL) {\r
354 return FALSE;\r
355 }\r
356\r
357 //\r
358 // Check whether the terminal device path is one of the variable instances.\r
359 //\r
360 ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);\r
361\r
362 FreePool (Variable);\r
363\r
364 return ReturnFlag;\r
365}\r
366\r
367/**\r
368 Free notify functions list.\r
369\r
370 @param ListHead The list head\r
371\r
372 @retval EFI_SUCCESS Free the notify list successfully.\r
373 @retval EFI_INVALID_PARAMETER ListHead is NULL.\r
374\r
375**/\r
376EFI_STATUS\r
377TerminalFreeNotifyList (\r
378 IN OUT LIST_ENTRY *ListHead\r
379 )\r
380{\r
381 TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
382\r
383 if (ListHead == NULL) {\r
384 return EFI_INVALID_PARAMETER;\r
385 }\r
386 while (!IsListEmpty (ListHead)) {\r
387 NotifyNode = CR (\r
388 ListHead->ForwardLink,\r
389 TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
390 NotifyEntry,\r
391 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
392 );\r
393 RemoveEntryList (ListHead->ForwardLink);\r
394 FreePool (NotifyNode);\r
395 }\r
396\r
397 return EFI_SUCCESS;\r
398}\r
399\r
400\r
e49ef433 401/**\r
ab76200c 402 Start this driver on Controller by opening a Serial IO protocol,\r
8fd98315 403 reading Device Path, and creating a child handle with a Simple Text In,\r
404 Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
405 And store Console Device Environment Variables.\r
e49ef433 406\r
8fd98315 407 @param This Protocol instance pointer.\r
ab76200c 408 @param Controller Handle of device to bind driver to\r
8fd98315 409 @param RemainingDevicePath Optional parameter use to pick a specific child\r
410 device to start.\r
e49ef433 411\r
ab76200c 412 @retval EFI_SUCCESS This driver is added to Controller.\r
413 @retval EFI_ALREADY_STARTED This driver is already running on Controller.\r
414 @retval other This driver does not support this device.\r
e49ef433 415\r
416**/\r
95276127 417EFI_STATUS\r
418EFIAPI\r
419TerminalDriverBindingStart (\r
420 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
421 IN EFI_HANDLE Controller,\r
422 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
423 )\r
95276127 424{\r
425 EFI_STATUS Status;\r
426 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
427 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
428 VENDOR_DEVICE_PATH *Node;\r
429 VENDOR_DEVICE_PATH *DefaultNode;\r
430 EFI_SERIAL_IO_MODE *Mode;\r
431 UINTN SerialInTimeOut;\r
432 TERMINAL_DEV *TerminalDevice;\r
433 UINT8 TerminalType;\r
434 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
435 UINTN EntryCount;\r
436 UINTN Index;\r
437 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
c4f9201e 438 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
e3dcffcc 439 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextInput;\r
440 BOOLEAN ConInSelected;\r
441 BOOLEAN ConOutSelected;\r
442 BOOLEAN NullRemaining;\r
443 BOOLEAN SimTxtInInstalled;\r
444 BOOLEAN SimTxtOutInstalled;\r
445 BOOLEAN FirstEnter;\r
446\r
447 TerminalDevice = NULL;\r
448 DefaultNode = NULL;\r
449 ConInSelected = FALSE;\r
450 ConOutSelected = FALSE;\r
451 NullRemaining = TRUE;\r
452 SimTxtInInstalled = FALSE;\r
453 SimTxtOutInstalled = FALSE;\r
454 FirstEnter = FALSE;\r
95276127 455 //\r
456 // Get the Device Path Protocol to build the device path of the child device\r
457 //\r
458 Status = gBS->OpenProtocol (\r
459 Controller,\r
460 &gEfiDevicePathProtocolGuid,\r
461 (VOID **) &ParentDevicePath,\r
462 This->DriverBindingHandle,\r
463 Controller,\r
464 EFI_OPEN_PROTOCOL_BY_DRIVER\r
465 );\r
466 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
467 return Status;\r
468 }\r
95276127 469\r
470 //\r
471 // Open the Serial I/O Protocol BY_DRIVER. It might already be started.\r
472 //\r
473 Status = gBS->OpenProtocol (\r
474 Controller,\r
475 &gEfiSerialIoProtocolGuid,\r
476 (VOID **) &SerialIo,\r
477 This->DriverBindingHandle,\r
478 Controller,\r
479 EFI_OPEN_PROTOCOL_BY_DRIVER\r
480 );\r
481 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
482 return Status;\r
483 }\r
484\r
485 if (Status != EFI_ALREADY_STARTED) {\r
486 //\r
e3dcffcc 487 // the serial I/O protocol never be opened before, it is the first\r
488 // time to start the serial Io controller\r
95276127 489 //\r
e3dcffcc 490 FirstEnter = TRUE;\r
95276127 491 }\r
e3dcffcc 492\r
95276127 493 //\r
e3dcffcc 494 // Serial I/O is not already open by this driver, then tag the handle\r
495 // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and\r
496 // StdErrDev variables with the list of possible terminal types on this\r
497 // serial port.\r
95276127 498 //\r
e3dcffcc 499 Status = gBS->OpenProtocol (\r
95276127 500 Controller,\r
e3dcffcc 501 &gEfiCallerIdGuid,\r
502 NULL,\r
503 This->DriverBindingHandle,\r
504 Controller,\r
505 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
95276127 506 );\r
e3dcffcc 507 if (EFI_ERROR (Status)) {\r
508 Status = gBS->InstallMultipleProtocolInterfaces (\r
509 &Controller,\r
510 &gEfiCallerIdGuid,\r
511 DuplicateDevicePath (ParentDevicePath),\r
512 NULL\r
513 );\r
514 if (EFI_ERROR (Status)) {\r
515 goto Error;\r
95276127 516 }\r
517\r
e3dcffcc 518 if (!IsHotPlugDevice (ParentDevicePath)) {\r
519 //\r
520 // if the serial device is a hot plug device, do not update the\r
521 // ConInDev, ConOutDev, and StdErrDev variables.\r
522 //\r
523 TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
524 TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
525 TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
95276127 526 }\r
527 }\r
e3dcffcc 528\r
529 //\r
530 // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols\r
95276127 531 //\r
e3dcffcc 532 // Simple In/Out Protocol will not be installed onto the handle if the\r
533 // device path to the handle is not present in the ConIn/ConOut\r
534 // environment variable. But If RemainingDevicePath is NULL, then always\r
535 // produce both Simple In and Simple Text Output Protocols. This is required\r
536 // for the connect all sequences to make sure all possible consoles are\r
537 // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
95276127 538 //\r
539 if (RemainingDevicePath == NULL) {\r
e3dcffcc 540 NullRemaining = TRUE;\r
541 }\r
542\r
543 DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);\r
544 if (DevicePath != NULL) {\r
545 ConInSelected = IsTerminalInConsoleVariable (L"ConIn", DevicePath);\r
546 ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);\r
547 FreePool (DevicePath);\r
548 } else {\r
549 goto Error;\r
550 }\r
551 //\r
552 // Not create the child terminal handle if both Simple In/In Ex and\r
553 // Simple text Out protocols are not required to be published\r
554 //\r
555 if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {\r
556 goto Error;\r
557 }\r
558\r
559 //\r
560 // create the child terminal handle during first entry\r
561 //\r
562 if (FirstEnter) {\r
563 //\r
564 // First enther the start funciton\r
565 //\r
566 FirstEnter = FALSE;\r
567 //\r
568 // Make sure a child handle does not already exist. This driver can only\r
569 // produce one child per serial port.\r
570 //\r
571 Status = gBS->OpenProtocolInformation (\r
572 Controller,\r
573 &gEfiSerialIoProtocolGuid,\r
574 &OpenInfoBuffer,\r
575 &EntryCount\r
576 );\r
577 if (!EFI_ERROR (Status)) {\r
578 Status = EFI_SUCCESS;\r
579 for (Index = 0; Index < EntryCount; Index++) {\r
580 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
581 Status = EFI_ALREADY_STARTED;\r
582 }\r
583 }\r
584\r
585 FreePool (OpenInfoBuffer);\r
586 if (EFI_ERROR (Status)) {\r
587 goto Error;\r
588 }\r
589 }\r
590\r
591 //\r
592 // If RemainingDevicePath is NULL, then create default device path node\r
593 //\r
594 if (RemainingDevicePath == NULL) {\r
595 DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));\r
596 if (DefaultNode == NULL) {\r
597 Status = EFI_OUT_OF_RESOURCES;\r
598 goto Error;\r
599 }\r
600\r
188e4e84 601 TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
e3dcffcc 602 //\r
603 // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)\r
604 //\r
605 ASSERT (TerminalType <= VTUTF8TYPE);\r
606\r
607 CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));\r
608 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;\r
609 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
610 //\r
611 // If RemainingDevicePath isn't the End of Device Path Node,\r
612 // Use the RemainingDevicePath to determine the terminal type\r
613 //\r
614 Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;\r
615 if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
616 TerminalType = PCANSITYPE;\r
617 } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
618 TerminalType = VT100TYPE;\r
619 } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
620 TerminalType = VT100PLUSTYPE;\r
621 } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
622 TerminalType = VTUTF8TYPE;\r
623 } else {\r
624 goto Error;\r
625 }\r
626 } else {\r
627 //\r
628 // If RemainingDevicePath is the End of Device Path Node,\r
629 // skip enumerate any device and return EFI_SUCESSS\r
630 //\r
631 return EFI_SUCCESS;\r
632 }\r
633\r
634 //\r
635 // Initialize the Terminal Dev\r
636 //\r
637 TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
638 if (TerminalDevice == NULL) {\r
95276127 639 Status = EFI_OUT_OF_RESOURCES;\r
640 goto Error;\r
641 }\r
642\r
e3dcffcc 643 TerminalDevice->TerminalType = TerminalType;\r
644 TerminalDevice->SerialIo = SerialIo;\r
645\r
646 InitializeListHead (&TerminalDevice->NotifyList);\r
647 Status = gBS->CreateEvent (\r
648 EVT_NOTIFY_WAIT,\r
649 TPL_NOTIFY,\r
650 TerminalConInWaitForKeyEx,\r
651 &TerminalDevice->SimpleInputEx,\r
652 &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
653 );\r
654 if (EFI_ERROR (Status)) {\r
655 goto Error;\r
656 }\r
657\r
658 Status = gBS->CreateEvent (\r
659 EVT_NOTIFY_WAIT,\r
660 TPL_NOTIFY,\r
661 TerminalConInWaitForKey,\r
662 &TerminalDevice->SimpleInput,\r
663 &TerminalDevice->SimpleInput.WaitForKey\r
664 );\r
665 if (EFI_ERROR (Status)) {\r
666 goto Error;\r
667 }\r
8fd98315 668 //\r
e3dcffcc 669 // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
670 // the pre-read pending characters.\r
8fd98315 671 //\r
e3dcffcc 672 TerminalDevice->RawFiFo = AllocateZeroPool (sizeof (RAW_DATA_FIFO));\r
673 if (TerminalDevice->RawFiFo == NULL) {\r
674 goto Error;\r
675 }\r
676 TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
677 if (TerminalDevice->UnicodeFiFo == NULL) {\r
678 goto Error;\r
679 }\r
680 TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
681 if (TerminalDevice->EfiKeyFiFo == NULL) {\r
682 goto Error;\r
683 }\r
95276127 684\r
6b88ceec 685 //\r
e3dcffcc 686 // Set the timeout value of serial buffer for\r
687 // keystroke response performance issue\r
6b88ceec 688 //\r
e3dcffcc 689 Mode = TerminalDevice->SerialIo->Mode;\r
690\r
691 SerialInTimeOut = 0;\r
692 if (Mode->BaudRate != 0) {\r
693 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
694 }\r
695\r
696 Status = TerminalDevice->SerialIo->SetAttributes (\r
697 TerminalDevice->SerialIo,\r
698 Mode->BaudRate,\r
699 Mode->ReceiveFifoDepth,\r
700 (UINT32) SerialInTimeOut,\r
701 (EFI_PARITY_TYPE) (Mode->Parity),\r
702 (UINT8) Mode->DataBits,\r
703 (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
704 );\r
705 if (EFI_ERROR (Status)) {\r
706 //\r
707 // if set attributes operation fails, invalidate\r
708 // the value of SerialInTimeOut,thus make it\r
709 // inconsistent with the default timeout value\r
710 // of serial buffer. This will invoke the recalculation\r
711 // in the readkeystroke routine.\r
712 //\r
713 TerminalDevice->SerialInTimeOut = 0;\r
6b88ceec 714 } else {\r
e3dcffcc 715 TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
6b88ceec 716 }\r
af4a6385 717 //\r
e3dcffcc 718 // Set Simple Text Output Protocol from template.\r
719 //\r
720 SimpleTextOutput = CopyMem (\r
721 &TerminalDevice->SimpleTextOutput,\r
722 &mTerminalDevTemplate.SimpleTextOutput,\r
723 sizeof (mTerminalDevTemplate.SimpleTextOutput)\r
724 );\r
725 SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
726\r
9875a3e3 727 TerminalDevice->SimpleTextOutputMode.MaxMode = TERMINAL_MAX_MODE;\r
e3dcffcc 728 //\r
729 // For terminal devices, cursor is always visible\r
730 //\r
731 TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;\r
732 Status = TerminalConOutSetAttribute (\r
733 SimpleTextOutput,\r
734 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
735 );\r
736 if (EFI_ERROR (Status)) {\r
737 goto ReportError;\r
738 }\r
6b88ceec 739\r
e3dcffcc 740 //\r
741 // Build the component name for the child device\r
742 //\r
743 TerminalDevice->ControllerNameTable = NULL;\r
744 switch (TerminalDevice->TerminalType) {\r
745 case PCANSITYPE:\r
746 AddUnicodeString2 (\r
747 "eng",\r
748 gTerminalComponentName.SupportedLanguages,\r
749 &TerminalDevice->ControllerNameTable,\r
750 (CHAR16 *)L"PC-ANSI Serial Console",\r
751 TRUE\r
752 );\r
753 AddUnicodeString2 (\r
754 "en",\r
755 gTerminalComponentName2.SupportedLanguages,\r
756 &TerminalDevice->ControllerNameTable,\r
757 (CHAR16 *)L"PC-ANSI Serial Console",\r
758 FALSE\r
759 );\r
95276127 760\r
e3dcffcc 761 break;\r
66aa04e4 762\r
e3dcffcc 763 case VT100TYPE:\r
764 AddUnicodeString2 (\r
765 "eng",\r
766 gTerminalComponentName.SupportedLanguages,\r
767 &TerminalDevice->ControllerNameTable,\r
768 (CHAR16 *)L"VT-100 Serial Console",\r
769 TRUE\r
770 );\r
771 AddUnicodeString2 (\r
772 "en",\r
773 gTerminalComponentName2.SupportedLanguages,\r
774 &TerminalDevice->ControllerNameTable,\r
775 (CHAR16 *)L"VT-100 Serial Console",\r
776 FALSE\r
777 );\r
778\r
779 break;\r
780\r
781 case VT100PLUSTYPE:\r
782 AddUnicodeString2 (\r
783 "eng",\r
784 gTerminalComponentName.SupportedLanguages,\r
785 &TerminalDevice->ControllerNameTable,\r
786 (CHAR16 *)L"VT-100+ Serial Console",\r
787 TRUE\r
788 );\r
789 AddUnicodeString2 (\r
790 "en",\r
791 gTerminalComponentName2.SupportedLanguages,\r
792 &TerminalDevice->ControllerNameTable,\r
793 (CHAR16 *)L"VT-100+ Serial Console",\r
794 FALSE\r
795 );\r
796\r
797 break;\r
798\r
799 case VTUTF8TYPE:\r
800 AddUnicodeString2 (\r
801 "eng",\r
802 gTerminalComponentName.SupportedLanguages,\r
803 &TerminalDevice->ControllerNameTable,\r
804 (CHAR16 *)L"VT-UTF8 Serial Console",\r
805 TRUE\r
806 );\r
807 AddUnicodeString2 (\r
808 "en",\r
809 gTerminalComponentName2.SupportedLanguages,\r
810 &TerminalDevice->ControllerNameTable,\r
811 (CHAR16 *)L"VT-UTF8 Serial Console",\r
812 FALSE\r
813 );\r
814\r
815 break;\r
816 }\r
95276127 817\r
95276127 818 //\r
e3dcffcc 819 // Build the device path for the child device\r
95276127 820 //\r
e3dcffcc 821 Status = SetTerminalDevicePath (\r
822 TerminalDevice->TerminalType,\r
823 ParentDevicePath,\r
824 &TerminalDevice->DevicePath\r
825 );\r
826 if (EFI_ERROR (Status)) {\r
827 goto Error;\r
828 }\r
95276127 829\r
abef1c7a 830 Status = TerminalConOutReset (SimpleTextOutput, FALSE);\r
831 if (EFI_ERROR (Status)) {\r
832 goto ReportError;\r
833 }\r
834\r
835 Status = TerminalConOutSetMode (SimpleTextOutput, 0);\r
836 if (EFI_ERROR (Status)) {\r
837 goto ReportError;\r
838 }\r
839\r
840 Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);\r
841 if (EFI_ERROR (Status)) {\r
842 goto ReportError;\r
843 }\r
844\r
845 Status = gBS->CreateEvent (\r
846 EVT_TIMER,\r
847 TPL_CALLBACK,\r
848 NULL,\r
849 NULL,\r
850 &TerminalDevice->TwoSecondTimeOut\r
851 );\r
852\r
e3dcffcc 853 Status = gBS->InstallProtocolInterface (\r
854 &TerminalDevice->Handle,\r
855 &gEfiDevicePathProtocolGuid,\r
856 EFI_NATIVE_INTERFACE,\r
857 TerminalDevice->DevicePath\r
858 );\r
859 if (EFI_ERROR (Status)) {\r
860 goto Error;\r
861 }\r
95276127 862\r
95276127 863 //\r
e3dcffcc 864 // Register the Parent-Child relationship via\r
865 // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
95276127 866 //\r
e3dcffcc 867 Status = gBS->OpenProtocol (\r
868 Controller,\r
869 &gEfiSerialIoProtocolGuid,\r
870 (VOID **) &TerminalDevice->SerialIo,\r
871 This->DriverBindingHandle,\r
872 TerminalDevice->Handle,\r
873 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
874 );\r
875 if (EFI_ERROR (Status)) {\r
876 goto Error;\r
877 }\r
95276127 878 }\r
95276127 879\r
3012ce5c 880 //\r
e3dcffcc 881 // Find the child handle, and get its TerminalDevice private data\r
3012ce5c 882 //\r
e3dcffcc 883 Status = gBS->OpenProtocolInformation (\r
884 Controller,\r
885 &gEfiSerialIoProtocolGuid,\r
886 &OpenInfoBuffer,\r
887 &EntryCount\r
888 );\r
889 if (!EFI_ERROR (Status)) {\r
890 Status = EFI_NOT_FOUND;\r
891 ASSERT (OpenInfoBuffer != NULL);\r
892 for (Index = 0; Index < EntryCount; Index++) {\r
893 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
894 //\r
895 // Find the child terminal handle.\r
896 // Test whether the SimpleTxtIn and SimpleTxtOut have been published\r
897 //\r
898 Status = gBS->OpenProtocol (\r
899 OpenInfoBuffer[Index].ControllerHandle,\r
900 &gEfiSimpleTextInProtocolGuid,\r
901 (VOID **) &SimpleTextInput,\r
902 This->DriverBindingHandle,\r
903 OpenInfoBuffer[Index].ControllerHandle,\r
904 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
905 );\r
906 if (!EFI_ERROR (Status)) {\r
907 SimTxtInInstalled = TRUE;\r
908 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
909 }\r
3012ce5c 910\r
e3dcffcc 911 Status = gBS->OpenProtocol (\r
912 OpenInfoBuffer[Index].ControllerHandle,\r
913 &gEfiSimpleTextOutProtocolGuid,\r
914 (VOID **) &SimpleTextOutput,\r
915 This->DriverBindingHandle,\r
916 OpenInfoBuffer[Index].ControllerHandle,\r
917 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
918 );\r
919 if (!EFI_ERROR (Status)) {\r
920 SimTxtOutInstalled = TRUE;\r
921 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
922 }\r
923 Status = EFI_SUCCESS;\r
924 break;\r
925 }\r
926 }\r
95276127 927\r
e3dcffcc 928 FreePool (OpenInfoBuffer);\r
929 if (EFI_ERROR (Status)) {\r
930 goto ReportError;\r
931 }\r
932 } else {\r
95276127 933 goto ReportError;\r
934 }\r
935\r
e3dcffcc 936 ASSERT (TerminalDevice != NULL);\r
937 //\r
938 // Only do the reset if the device path is in the Conout variable\r
939 //\r
940 if (ConInSelected && !SimTxtInInstalled) {\r
941 Status = TerminalDevice->SimpleInput.Reset (\r
942 &TerminalDevice->SimpleInput,\r
943 FALSE\r
944 );\r
945 if (EFI_ERROR (Status)) {\r
946 //\r
947 // Need to report Error Code first\r
948 //\r
949 goto ReportError;\r
950 }\r
95276127 951 }\r
95276127 952\r
95276127 953 //\r
e3dcffcc 954 // Only output the configure string to remote terminal if the device path\r
955 // is in the Conout variable\r
95276127 956 //\r
e3dcffcc 957 if (ConOutSelected && !SimTxtOutInstalled) {\r
958 Status = TerminalDevice->SimpleTextOutput.SetAttribute (\r
959 &TerminalDevice->SimpleTextOutput,\r
960 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
961 );\r
962 if (EFI_ERROR (Status)) {\r
963 goto ReportError;\r
964 }\r
5bca971e 965\r
e3dcffcc 966 Status = TerminalDevice->SimpleTextOutput.Reset (\r
967 &TerminalDevice->SimpleTextOutput,\r
968 FALSE\r
969 );\r
970 if (EFI_ERROR (Status)) {\r
971 goto ReportError;\r
972 }\r
95276127 973\r
e3dcffcc 974 Status = TerminalDevice->SimpleTextOutput.SetMode (\r
975 &TerminalDevice->SimpleTextOutput,\r
976 0\r
977 );\r
978 if (EFI_ERROR (Status)) {\r
979 goto ReportError;\r
980 }\r
5bca971e 981\r
e3dcffcc 982 Status = TerminalDevice->SimpleTextOutput.EnableCursor (\r
983 &TerminalDevice->SimpleTextOutput,\r
984 TRUE\r
985 );\r
986 if (EFI_ERROR (Status)) {\r
987 goto ReportError;\r
988 }\r
95276127 989 }\r
f1aec6cc 990\r
95276127 991 //\r
e3dcffcc 992 // Simple In/Out Protocol will not be installed onto the handle if the\r
993 // device path to the handle is not present in the ConIn/ConOut\r
994 // environment variable. But If RemainingDevicePath is NULL, then always\r
995 // produce both Simple In and Simple Text Output Protocols. This is required\r
996 // for the connect all sequences to make sure all possible consoles are\r
997 // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
95276127 998 //\r
e3dcffcc 999 if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {\r
1000 Status = gBS->InstallMultipleProtocolInterfaces (\r
1001 &TerminalDevice->Handle,\r
1002 &gEfiSimpleTextInProtocolGuid,\r
1003 &TerminalDevice->SimpleInput,\r
1004 &gEfiSimpleTextInputExProtocolGuid,\r
1005 &TerminalDevice->SimpleInputEx,\r
1006 NULL\r
1007 );\r
1008 if (EFI_ERROR (Status)) {\r
1009 goto Error;\r
1010 }\r
95276127 1011 }\r
1012\r
e3dcffcc 1013 if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {\r
1014 Status = gBS->InstallProtocolInterface (\r
1015 &TerminalDevice->Handle,\r
1016 &gEfiSimpleTextOutProtocolGuid,\r
1017 EFI_NATIVE_INTERFACE,\r
1018 &TerminalDevice->SimpleTextOutput\r
1019 );\r
1020 if (EFI_ERROR (Status)) {\r
1021 goto Error;\r
1022 }\r
1023 }\r
95276127 1024 if (DefaultNode != NULL) {\r
1025 FreePool (DefaultNode);\r
1026 }\r
1027\r
1028 return EFI_SUCCESS;\r
1029\r
1030ReportError:\r
1031 //\r
1032 // Report error code before exiting\r
1033 //\r
e3dcffcc 1034 DevicePath = ParentDevicePath;\r
95276127 1035 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1036 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
f9876ecf 1037 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
95276127 1038 DevicePath\r
1039 );\r
1040\r
1041Error:\r
1042 //\r
1043 // Use the Stop() function to free all resources allocated in Start()\r
1044 //\r
1045 if (TerminalDevice != NULL) {\r
1046\r
1047 if (TerminalDevice->Handle != NULL) {\r
1048 This->Stop (This, Controller, 1, &TerminalDevice->Handle);\r
1049 } else {\r
1050\r
1051 if (TerminalDevice->TwoSecondTimeOut != NULL) {\r
1052 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
1053 }\r
1054\r
1055 if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
1056 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
1057 }\r
1058\r
66aa04e4 1059 if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
1060 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
1061 }\r
1062\r
1063 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
1064\r
5c998646 1065 if (TerminalDevice->RawFiFo != NULL) {\r
1066 FreePool (TerminalDevice->RawFiFo);\r
1067 }\r
1068 if (TerminalDevice->UnicodeFiFo != NULL) {\r
1069 FreePool (TerminalDevice->UnicodeFiFo);\r
1070 }\r
1071 if (TerminalDevice->EfiKeyFiFo != NULL) {\r
1072 FreePool (TerminalDevice->EfiKeyFiFo);\r
1073 }\r
1074\r
95276127 1075 if (TerminalDevice->ControllerNameTable != NULL) {\r
1076 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
1077 }\r
1078\r
1079 if (TerminalDevice->DevicePath != NULL) {\r
1080 FreePool (TerminalDevice->DevicePath);\r
1081 }\r
1082\r
1083 FreePool (TerminalDevice);\r
1084 }\r
1085 }\r
1086\r
1087 if (DefaultNode != NULL) {\r
1088 FreePool (DefaultNode);\r
1089 }\r
1090\r
1091 This->Stop (This, Controller, 0, NULL);\r
1092\r
1093 return Status;\r
1094}\r
1095\r
e49ef433 1096/**\r
ab76200c 1097 Stop this driver on Controller by closing Simple Text In, Simple Text\r
8fd98315 1098 In Ex, Simple Text Out protocol, and removing parent device path from\r
677fdb90 1099 Console Device Environment Variables.\r
e49ef433 1100\r
8fd98315 1101 @param This Protocol instance pointer.\r
ab76200c 1102 @param Controller Handle of device to stop driver on\r
8fd98315 1103 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
1104 children is zero stop the entire bus driver.\r
1105 @param ChildHandleBuffer List of Child Handles to Stop.\r
e49ef433 1106\r
ab76200c 1107 @retval EFI_SUCCESS This driver is removed Controller.\r
8fd98315 1108 @retval other This driver could not be removed from this device.\r
e49ef433 1109\r
1110**/\r
95276127 1111EFI_STATUS\r
1112EFIAPI\r
1113TerminalDriverBindingStop (\r
1114 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1115 IN EFI_HANDLE Controller,\r
1116 IN UINTN NumberOfChildren,\r
1117 IN EFI_HANDLE *ChildHandleBuffer\r
1118 )\r
95276127 1119{\r
1120 EFI_STATUS Status;\r
1121 UINTN Index;\r
1122 BOOLEAN AllChildrenStopped;\r
1123 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOutput;\r
1124 TERMINAL_DEV *TerminalDevice;\r
1125 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1126 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
1127 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1128\r
1129 Status = gBS->HandleProtocol (\r
1130 Controller,\r
1131 &gEfiDevicePathProtocolGuid,\r
1132 (VOID **) &DevicePath\r
1133 );\r
1134 if (EFI_ERROR (Status)) {\r
1135 return Status;\r
1136 }\r
95276127 1137\r
1138 //\r
1139 // Complete all outstanding transactions to Controller.\r
1140 // Don't allow any new transaction to Controller to be started.\r
1141 //\r
1142 if (NumberOfChildren == 0) {\r
1143 //\r
1144 // Close the bus driver\r
1145 //\r
1146 Status = gBS->OpenProtocol (\r
1147 Controller,\r
1148 &gEfiCallerIdGuid,\r
1149 (VOID **) &ParentDevicePath,\r
1150 This->DriverBindingHandle,\r
1151 Controller,\r
1152 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1153 );\r
1154 if (!EFI_ERROR (Status)) {\r
1155 //\r
1156 // Remove Parent Device Path from\r
1157 // the Console Device Environment Variables\r
1158 //\r
ff37790d
A
1159 TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
1160 TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
1161 TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
95276127 1162\r
1163 //\r
1164 // Uninstall the Terminal Driver's GUID Tag from the Serial controller\r
1165 //\r
1166 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1167 Controller,\r
1168 &gEfiCallerIdGuid,\r
1169 ParentDevicePath,\r
1170 NULL\r
1171 );\r
1172\r
1173 //\r
1174 // Free the ParentDevicePath that was duplicated in Start()\r
1175 //\r
1176 if (!EFI_ERROR (Status)) {\r
1177 FreePool (ParentDevicePath);\r
1178 }\r
1179 }\r
1180\r
1181 gBS->CloseProtocol (\r
1182 Controller,\r
1183 &gEfiSerialIoProtocolGuid,\r
1184 This->DriverBindingHandle,\r
1185 Controller\r
1186 );\r
1187\r
1188 gBS->CloseProtocol (\r
1189 Controller,\r
1190 &gEfiDevicePathProtocolGuid,\r
1191 This->DriverBindingHandle,\r
1192 Controller\r
1193 );\r
1194\r
1195 return EFI_SUCCESS;\r
1196 }\r
1197\r
1198 AllChildrenStopped = TRUE;\r
1199\r
1200 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1201\r
1202 Status = gBS->OpenProtocol (\r
1203 ChildHandleBuffer[Index],\r
1204 &gEfiSimpleTextOutProtocolGuid,\r
1205 (VOID **) &SimpleTextOutput,\r
1206 This->DriverBindingHandle,\r
1207 ChildHandleBuffer[Index],\r
1208 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1209 );\r
1210 if (!EFI_ERROR (Status)) {\r
1211\r
1212 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
1213\r
1214 gBS->CloseProtocol (\r
1215 Controller,\r
1216 &gEfiSerialIoProtocolGuid,\r
1217 This->DriverBindingHandle,\r
1218 ChildHandleBuffer[Index]\r
1219 );\r
1220\r
1221 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1222 ChildHandleBuffer[Index],\r
1223 &gEfiSimpleTextInProtocolGuid,\r
1224 &TerminalDevice->SimpleInput,\r
66aa04e4 1225 &gEfiSimpleTextInputExProtocolGuid,\r
1226 &TerminalDevice->SimpleInputEx,\r
95276127 1227 &gEfiSimpleTextOutProtocolGuid,\r
1228 &TerminalDevice->SimpleTextOutput,\r
1229 &gEfiDevicePathProtocolGuid,\r
1230 TerminalDevice->DevicePath,\r
1231 NULL\r
1232 );\r
1233 if (EFI_ERROR (Status)) {\r
1234 gBS->OpenProtocol (\r
1235 Controller,\r
1236 &gEfiSerialIoProtocolGuid,\r
1237 (VOID **) &SerialIo,\r
1238 This->DriverBindingHandle,\r
1239 ChildHandleBuffer[Index],\r
1240 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1241 );\r
1242 } else {\r
1243\r
1244 if (TerminalDevice->ControllerNameTable != NULL) {\r
1245 FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
1246 }\r
1247\r
95276127 1248 gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
1249 gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
66aa04e4 1250 gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
1251 TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
95276127 1252 FreePool (TerminalDevice->DevicePath);\r
1253 FreePool (TerminalDevice);\r
1254 }\r
1255 }\r
1256\r
1257 if (EFI_ERROR (Status)) {\r
1258 AllChildrenStopped = FALSE;\r
1259 }\r
1260 }\r
1261\r
1262 if (!AllChildrenStopped) {\r
1263 return EFI_DEVICE_ERROR;\r
1264 }\r
1265\r
1266 return EFI_SUCCESS;\r
1267}\r
1268\r
8fd98315 1269/**\r
1270 Update terminal device path in Console Device Environment Variables.\r
1271\r
1272 @param VariableName The Console Device Environment Variable.\r
11baadb6 1273 @param ParentDevicePath The terminal device path to be updated.\r
8fd98315 1274\r
8fd98315 1275**/\r
95276127 1276VOID\r
1277TerminalUpdateConsoleDevVariable (\r
1278 IN CHAR16 *VariableName,\r
1279 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1280 )\r
1281{\r
1282 EFI_STATUS Status;\r
1283 UINTN VariableSize;\r
1284 UINT8 TerminalType;\r
1285 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1286 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1287 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1288\r
95276127 1289 //\r
1290 // Get global variable and its size according to the name given.\r
1291 //\r
e3dcffcc 1292 Variable = GetEfiGlobalVariable (VariableName);\r
1293 if (Variable == NULL) {\r
1294 return;\r
1295 }\r
1296\r
95276127 1297 //\r
1298 // Append terminal device path onto the variable.\r
1299 //\r
e49ef433 1300 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {\r
95276127 1301 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1302 NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
1303 if (Variable != NULL) {\r
1304 FreePool (Variable);\r
1305 }\r
1306\r
1307 if (TempDevicePath != NULL) {\r
1308 FreePool (TempDevicePath);\r
1309 }\r
1310\r
1311 Variable = NewVariable;\r
1312 }\r
1313\r
1314 VariableSize = GetDevicePathSize (Variable);\r
1315\r
1316 Status = gRT->SetVariable (\r
1317 VariableName,\r
1318 &gEfiGlobalVariableGuid,\r
1319 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1320 VariableSize,\r
1321 Variable\r
1322 );\r
1323 ASSERT_EFI_ERROR (Status);\r
1324 FreePool (Variable);\r
1325\r
1326 return ;\r
1327}\r
1328\r
e49ef433 1329\r
1330/**\r
8fd98315 1331 Remove terminal device path from Console Device Environment Variables.\r
e49ef433 1332\r
8fd98315 1333 @param VariableName Console Device Environment Variables.\r
11baadb6 1334 @param ParentDevicePath The terminal device path to be updated.\r
e49ef433 1335\r
e49ef433 1336**/\r
95276127 1337VOID\r
1338TerminalRemoveConsoleDevVariable (\r
1339 IN CHAR16 *VariableName,\r
1340 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
1341 )\r
95276127 1342{\r
1343 EFI_STATUS Status;\r
1344 BOOLEAN FoundOne;\r
1345 BOOLEAN Match;\r
1346 UINTN VariableSize;\r
1347 UINTN InstanceSize;\r
1348 UINT8 TerminalType;\r
1349 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
1350 EFI_DEVICE_PATH_PROTOCOL *Variable;\r
1351 EFI_DEVICE_PATH_PROTOCOL *OriginalVariable;\r
1352 EFI_DEVICE_PATH_PROTOCOL *NewVariable;\r
1353 EFI_DEVICE_PATH_PROTOCOL *SavedNewVariable;\r
1354 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1355\r
95276127 1356 Instance = NULL;\r
1357\r
1358 //\r
1359 // Get global variable and its size according to the name given.\r
1360 //\r
e3dcffcc 1361 Variable = GetEfiGlobalVariable (VariableName);\r
95276127 1362 if (Variable == NULL) {\r
1363 return ;\r
1364 }\r
1365\r
1366 FoundOne = FALSE;\r
1367 OriginalVariable = Variable;\r
1368 NewVariable = NULL;\r
1369\r
1370 //\r
1371 // Get first device path instance from Variable\r
1372 //\r
1373 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1374 if (Instance == NULL) {\r
1375 FreePool (OriginalVariable);\r
1376 return ;\r
1377 }\r
1378 //\r
1379 // Loop through all the device path instances of Variable\r
1380 //\r
1381 do {\r
1382 //\r
1383 // Loop through all the terminal types that this driver supports\r
1384 //\r
1385 Match = FALSE;\r
e49ef433 1386 for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {\r
95276127 1387\r
1388 SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
1389\r
1390 //\r
11baadb6 1391 // Compare the generated device path to the current device path instance\r
95276127 1392 //\r
1393 if (TempDevicePath != NULL) {\r
1394 if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {\r
1395 Match = TRUE;\r
1396 FoundOne = TRUE;\r
1397 }\r
1398\r
1399 FreePool (TempDevicePath);\r
1400 }\r
1401 }\r
1402 //\r
1403 // If a match was not found, then keep the current device path instance\r
1404 //\r
1405 if (!Match) {\r
1406 SavedNewVariable = NewVariable;\r
1407 NewVariable = AppendDevicePathInstance (NewVariable, Instance);\r
1408 if (SavedNewVariable != NULL) {\r
1409 FreePool (SavedNewVariable);\r
1410 }\r
1411 }\r
1412 //\r
1413 // Get next device path instance from Variable\r
1414 //\r
1415 FreePool (Instance);\r
1416 Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);\r
1417 } while (Instance != NULL);\r
1418\r
1419 FreePool (OriginalVariable);\r
1420\r
1421 if (FoundOne) {\r
1422 VariableSize = GetDevicePathSize (NewVariable);\r
1423\r
1424 Status = gRT->SetVariable (\r
1425 VariableName,\r
1426 &gEfiGlobalVariableGuid,\r
1427 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1428 VariableSize,\r
1429 NewVariable\r
1430 );\r
1431 ASSERT_EFI_ERROR (Status);\r
1432 }\r
1433\r
1434 if (NewVariable != NULL) {\r
1435 FreePool (NewVariable);\r
1436 }\r
1437\r
1438 return ;\r
1439}\r
1440\r
8fd98315 1441/**\r
11baadb6 1442 Build terminal device path according to terminal type.\r
8fd98315 1443\r
1444 @param TerminalType The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
11baadb6 1445 @param ParentDevicePath Parent device path.\r
8fd98315 1446 @param TerminalDevicePath Returned terminal device path, if building successfully.\r
1447\r
1448 @retval EFI_UNSUPPORTED Terminal does not belong to the supported type.\r
1449 @retval EFI_OUT_OF_RESOURCES Generate terminal device path failed.\r
1450 @retval EFI_SUCCESS Build terminal device path successfully.\r
1451\r
1452**/\r
95276127 1453EFI_STATUS\r
1454SetTerminalDevicePath (\r
1455 IN UINT8 TerminalType,\r
1456 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1457 OUT EFI_DEVICE_PATH_PROTOCOL **TerminalDevicePath\r
1458 )\r
1459{\r
1460 VENDOR_DEVICE_PATH Node;\r
1461\r
1462 *TerminalDevicePath = NULL;\r
1463 Node.Header.Type = MESSAGING_DEVICE_PATH;\r
1464 Node.Header.SubType = MSG_VENDOR_DP;\r
1465\r
1466 //\r
ab76200c 1467 // Generate terminal device path node according to terminal type.\r
95276127 1468 //\r
1469 switch (TerminalType) {\r
1470\r
e49ef433 1471 case PCANSITYPE:\r
ab76200c 1472 CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);\r
95276127 1473 break;\r
1474\r
e49ef433 1475 case VT100TYPE:\r
ab76200c 1476 CopyGuid (&Node.Guid, &gEfiVT100Guid);\r
95276127 1477 break;\r
1478\r
e49ef433 1479 case VT100PLUSTYPE:\r
ab76200c 1480 CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);\r
95276127 1481 break;\r
1482\r
e49ef433 1483 case VTUTF8TYPE:\r
ab76200c 1484 CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);\r
95276127 1485 break;\r
1486\r
1487 default:\r
1488 return EFI_UNSUPPORTED;\r
95276127 1489 }\r
1490\r
ab76200c 1491 //\r
1492 // Get VENDOR_DEVCIE_PATH size and put into Node.Header\r
1493 //\r
95276127 1494 SetDevicePathNodeLength (\r
1495 &Node.Header,\r
1496 sizeof (VENDOR_DEVICE_PATH)\r
1497 );\r
ab76200c 1498\r
95276127 1499 //\r
ab76200c 1500 // Append the terminal node onto parent device path\r
95276127 1501 // to generate a complete terminal device path.\r
1502 //\r
1503 *TerminalDevicePath = AppendDevicePathNode (\r
1504 ParentDevicePath,\r
1505 (EFI_DEVICE_PATH_PROTOCOL *) &Node\r
1506 );\r
1507 if (*TerminalDevicePath == NULL) {\r
1508 return EFI_OUT_OF_RESOURCES;\r
1509 }\r
1510\r
1511 return EFI_SUCCESS;\r
1512}\r
1513\r
97a079ed
A
1514/**\r
1515 The user Entry Point for module Terminal. The user code starts with this function.\r
1516\r
ab76200c 1517 @param ImageHandle The firmware allocated handle for the EFI image.\r
1518 @param SystemTable A pointer to the EFI System Table.\r
fb0b259e 1519\r
97a079ed
A
1520 @retval EFI_SUCCESS The entry point is executed successfully.\r
1521 @retval other Some error occurs when executing this entry point.\r
1522\r
1523**/\r
1524EFI_STATUS\r
1525EFIAPI\r
1526InitializeTerminal(\r
1527 IN EFI_HANDLE ImageHandle,\r
1528 IN EFI_SYSTEM_TABLE *SystemTable\r
1529 )\r
1530{\r
1531 EFI_STATUS Status;\r
1532\r
1533 //\r
1534 // Install driver model protocol(s).\r
1535 //\r
5bca971e 1536 Status = EfiLibInstallDriverBindingComponentName2 (\r
97a079ed
A
1537 ImageHandle,\r
1538 SystemTable,\r
1539 &gTerminalDriverBinding,\r
1540 ImageHandle,\r
1541 &gTerminalComponentName,\r
5bca971e 1542 &gTerminalComponentName2\r
97a079ed
A
1543 );\r
1544 ASSERT_EFI_ERROR (Status);\r
1545\r
97a079ed
A
1546 return Status;\r
1547}\r
f1aec6cc 1548\r
1549/**\r
1550 Check if the device supports hot-plug through its device path.\r
1551\r
1552 This function could be updated to check more types of Hot Plug devices.\r
1553 Currently, it checks USB and PCCard device.\r
1554\r
1555 @param DevicePath Pointer to device's device path.\r
1556\r
1557 @retval TRUE The devcie is a hot-plug device\r
1558 @retval FALSE The devcie is not a hot-plug device.\r
1559\r
1560**/\r
1561BOOLEAN\r
1562IsHotPlugDevice (\r
1563 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1564 )\r
1565{\r
1566 EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath;\r
1567\r
1568 CheckDevicePath = DevicePath;\r
1569 while (!IsDevicePathEnd (CheckDevicePath)) {\r
1570 //\r
1571 // Check device whether is hot plug device or not throught Device Path\r
e3dcffcc 1572 //\r
f1aec6cc 1573 if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1574 (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||\r
1575 DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||\r
1576 DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {\r
1577 //\r
1578 // If Device is USB device\r
1579 //\r
1580 return TRUE;\r
1581 }\r
1582 if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&\r
1583 (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {\r
1584 //\r
1585 // If Device is PCCard\r
1586 //\r
1587 return TRUE;\r
1588 }\r
e3dcffcc 1589\r
f1aec6cc 1590 CheckDevicePath = NextDevicePathNode (CheckDevicePath);\r
1591 }\r
1592\r
1593 return FALSE;\r
1594}\r
1595\r