]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
Code scrub for Universal\Console\TerminalDxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / TerminalConIn.c
1 /** @file
2 Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
3
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Terminal.h"
16
17
18 /**
19 Reads the next keystroke from the input device. The WaitForKey Event can
20 be used to test for existence of a keystroke via WaitForEvent () call.
21
22 @param TerminalDevice Terminal driver private structure
23 @param KeyData A pointer to a buffer that is filled in with the
24 keystroke state data for the key that was
25 pressed.
26
27 @retval EFI_SUCCESS The keystroke information was returned.
28 @retval EFI_NOT_READY There was no keystroke data available.
29 @retval EFI_DEVICE_ERROR The keystroke information was not returned due
30 to hardware errors.
31 @retval EFI_INVALID_PARAMETER KeyData is NULL.
32
33 **/
34 EFI_STATUS
35 ReadKeyStrokeWorker (
36 IN TERMINAL_DEV *TerminalDevice,
37 OUT EFI_KEY_DATA *KeyData
38 )
39 {
40 EFI_STATUS Status;
41 LIST_ENTRY *Link;
42 LIST_ENTRY *NotifyList;
43 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
44
45 if (KeyData == NULL) {
46 return EFI_INVALID_PARAMETER;
47 }
48
49 //
50 // Initialize *Key to nonsense value.
51 //
52 KeyData->Key.ScanCode = SCAN_NULL;
53 KeyData->Key.UnicodeChar = 0;
54
55 Status = TerminalConInCheckForKey (&TerminalDevice->SimpleInput);
56 if (EFI_ERROR (Status)) {
57 return EFI_NOT_READY;
58 }
59
60 if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
61 return EFI_NOT_READY;
62 }
63
64 KeyData->KeyState.KeyShiftState = 0;
65 KeyData->KeyState.KeyToggleState = 0;
66
67 //
68 // Invoke notification functions if exist
69 //
70 NotifyList = &TerminalDevice->NotifyList;
71 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
72 CurrentNotify = CR (
73 Link,
74 TERMINAL_CONSOLE_IN_EX_NOTIFY,
75 NotifyEntry,
76 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
77 );
78 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
79 CurrentNotify->KeyNotificationFn (KeyData);
80 }
81 }
82
83 return EFI_SUCCESS;
84
85 }
86
87 /**
88 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
89 This driver only perform dependent serial device reset regardless of
90 the value of ExtendeVerification
91
92 @param This Indicates the calling context.
93 @param ExtendedVerification Skip by this driver.
94
95 @return EFI_SUCCESS The reset operation succeeds.
96 @return EFI_DEVICE_ERROR The dependent serial port reset fails.
97
98 **/
99 EFI_STATUS
100 EFIAPI
101 TerminalConInReset (
102 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
103 IN BOOLEAN ExtendedVerification
104 )
105 {
106 EFI_STATUS Status;
107 TERMINAL_DEV *TerminalDevice;
108
109 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
110
111 //
112 // Report progress code here
113 //
114 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
115 EFI_PROGRESS_CODE,
116 PcdGet32 (PcdStatusCodeValueRemoteConsoleReset),
117 TerminalDevice->DevicePath
118 );
119
120 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
121
122 //
123 // clear all the internal buffer for keys
124 //
125 InitializeRawFiFo (TerminalDevice);
126 InitializeUnicodeFiFo (TerminalDevice);
127 InitializeEfiKeyFiFo (TerminalDevice);
128
129 if (EFI_ERROR (Status)) {
130 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
131 EFI_ERROR_CODE | EFI_ERROR_MINOR,
132 PcdGet32 (PcdStatusCodeValueRemoteConsoleError),
133 TerminalDevice->DevicePath
134 );
135 }
136
137 return Status;
138 }
139
140 /**
141 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
142
143 @param This Indicates the calling context.
144 @param Key A pointer to a buffer that is filled in with the
145 keystroke information for the key that was sent
146 from terminal.
147
148 @return EFI_SUCCESS The keystroke information is returned successfully.
149 @return EFI_NOT_READY There is no keystroke data available.
150 @return EFI_DEVICE_ERROR The dependent serial device encounters error.
151
152 **/
153 EFI_STATUS
154 EFIAPI
155 TerminalConInReadKeyStroke (
156 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
157 OUT EFI_INPUT_KEY *Key
158 )
159 {
160 TERMINAL_DEV *TerminalDevice;
161 EFI_STATUS Status;
162 EFI_KEY_DATA KeyData;
163
164 //
165 // get TERMINAL_DEV from "This" parameter.
166 //
167 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
168
169 Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
170 if (EFI_ERROR (Status)) {
171 return Status;
172 }
173
174 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
175
176 return EFI_SUCCESS;
177
178 }
179
180 /**
181 Check if the key already has been registered.
182
183 If both RegsiteredData and InputData is NULL, then ASSERT().
184
185 @param RegsiteredData A pointer to a buffer that is filled in with the
186 keystroke state data for the key that was
187 registered.
188 @param InputData A pointer to a buffer that is filled in with the
189 keystroke state data for the key that was
190 pressed.
191
192 @retval TRUE Key be pressed matches a registered key.
193 @retval FLASE Match failed.
194
195 **/
196 BOOLEAN
197 IsKeyRegistered (
198 IN EFI_KEY_DATA *RegsiteredData,
199 IN EFI_KEY_DATA *InputData
200 )
201 {
202 ASSERT (RegsiteredData != NULL && InputData != NULL);
203
204 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
205 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
206 return FALSE;
207 }
208
209 return TRUE;
210 }
211
212
213
214 /**
215 Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
216 Signal the event if there is key available
217
218 @param Event Indicates the event that invoke this function.
219 @param Context Indicates the calling context.
220
221 @return none.
222
223 **/
224 VOID
225 EFIAPI
226 TerminalConInWaitForKeyEx (
227 IN EFI_EVENT Event,
228 IN VOID *Context
229 )
230 {
231 TERMINAL_DEV *TerminalDevice;
232
233 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (Context);
234
235 TerminalConInWaitForKey (Event, &TerminalDevice->SimpleInput);
236
237 }
238
239 //
240 // Simple Text Input Ex protocol functions
241 //
242
243 /**
244 Reset the input device and optionally run diagnostics
245
246 @param This Protocol instance pointer.
247 @param ExtendedVerification Driver may perform diagnostics on reset.
248
249 @retval EFI_SUCCESS The device was reset.
250 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
251 not be reset.
252
253 **/
254 EFI_STATUS
255 EFIAPI
256 TerminalConInResetEx (
257 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
258 IN BOOLEAN ExtendedVerification
259 )
260 {
261 EFI_STATUS Status;
262 TERMINAL_DEV *TerminalDevice;
263
264 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
265
266 Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
267 if (EFI_ERROR (Status)) {
268 return EFI_DEVICE_ERROR;
269 }
270
271 return EFI_SUCCESS;
272
273 }
274
275
276 /**
277 Reads the next keystroke from the input device. The WaitForKey Event can
278 be used to test for existence of a keystroke via WaitForEvent () call.
279
280 @param This Protocol instance pointer.
281 @param KeyData A pointer to a buffer that is filled in with the
282 keystroke state data for the key that was
283 pressed.
284
285 @retval EFI_SUCCESS The keystroke information was returned.
286 @retval EFI_NOT_READY There was no keystroke data available.
287 @retval EFI_DEVICE_ERROR The keystroke information was not returned due
288 to hardware errors.
289 @retval EFI_INVALID_PARAMETER KeyData is NULL.
290
291 **/
292 EFI_STATUS
293 EFIAPI
294 TerminalConInReadKeyStrokeEx (
295 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
296 OUT EFI_KEY_DATA *KeyData
297 )
298 {
299 TERMINAL_DEV *TerminalDevice;
300
301 if (KeyData == NULL) {
302 return EFI_INVALID_PARAMETER;
303 }
304
305 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
306
307 return ReadKeyStrokeWorker (TerminalDevice, KeyData);
308
309 }
310
311
312 /**
313 Set certain state for the input device.
314
315 @param This Protocol instance pointer.
316 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
317 state for the input device.
318
319 @retval EFI_SUCCESS The device state was set successfully.
320 @retval EFI_DEVICE_ERROR The device is not functioning correctly and
321 could not have the setting adjusted.
322 @retval EFI_UNSUPPORTED The device does not have the ability to set its
323 state.
324 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
325
326 **/
327 EFI_STATUS
328 EFIAPI
329 TerminalConInSetState (
330 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
331 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
332 )
333 {
334 if (KeyToggleState == NULL) {
335 return EFI_INVALID_PARAMETER;
336 }
337
338 return EFI_SUCCESS;
339 }
340
341
342 /**
343 Register a notification function for a particular keystroke for the input device.
344
345 @param This Protocol instance pointer.
346 @param KeyData A pointer to a buffer that is filled in with the
347 keystroke information data for the key that was
348 pressed.
349 @param KeyNotificationFunction Points to the function to be called when the key
350 sequence is typed specified by KeyData.
351 @param NotifyHandle Points to the unique handle assigned to the
352 registered notification.
353
354 @retval EFI_SUCCESS The notification function was registered
355 successfully.
356 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data
357 structures.
358 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
359
360 **/
361 EFI_STATUS
362 EFIAPI
363 TerminalConInRegisterKeyNotify (
364 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
365 IN EFI_KEY_DATA *KeyData,
366 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
367 OUT EFI_HANDLE *NotifyHandle
368 )
369 {
370 EFI_STATUS Status;
371 TERMINAL_DEV *TerminalDevice;
372 TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify;
373 LIST_ENTRY *Link;
374 LIST_ENTRY *NotifyList;
375 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
376
377 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
378 return EFI_INVALID_PARAMETER;
379 }
380
381 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
382
383 //
384 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
385 //
386 NotifyList = &TerminalDevice->NotifyList;
387 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
388 CurrentNotify = CR (
389 Link,
390 TERMINAL_CONSOLE_IN_EX_NOTIFY,
391 NotifyEntry,
392 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
393 );
394 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
395 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
396 *NotifyHandle = CurrentNotify->NotifyHandle;
397 return EFI_SUCCESS;
398 }
399 }
400 }
401
402 //
403 // Allocate resource to save the notification function
404 //
405 NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
406 if (NewNotify == NULL) {
407 return EFI_OUT_OF_RESOURCES;
408 }
409
410 NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
411 NewNotify->KeyNotificationFn = KeyNotificationFunction;
412 CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData));
413 InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
414 //
415 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
416 //
417 Status = gBS->InstallMultipleProtocolInterfaces (
418 &NewNotify->NotifyHandle,
419 &gSimpleTextInExNotifyGuid,
420 NULL,
421 NULL
422 );
423 ASSERT_EFI_ERROR (Status);
424 *NotifyHandle = NewNotify->NotifyHandle;
425
426 return EFI_SUCCESS;
427 }
428
429
430 /**
431 Remove a registered notification function from a particular keystroke.
432
433 @param This Protocol instance pointer.
434 @param NotificationHandle The handle of the notification function being
435 unregistered.
436
437 @retval EFI_SUCCESS The notification function was unregistered
438 successfully.
439 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
440 @retval EFI_NOT_FOUND Can not find the matching entry in database.
441
442 **/
443 EFI_STATUS
444 EFIAPI
445 TerminalConInUnregisterKeyNotify (
446 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
447 IN EFI_HANDLE NotificationHandle
448 )
449 {
450 EFI_STATUS Status;
451 TERMINAL_DEV *TerminalDevice;
452 LIST_ENTRY *Link;
453 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
454 LIST_ENTRY *NotifyList;
455
456 if (NotificationHandle == NULL) {
457 return EFI_INVALID_PARAMETER;
458 }
459
460 Status = gBS->OpenProtocol (
461 NotificationHandle,
462 &gSimpleTextInExNotifyGuid,
463 NULL,
464 NULL,
465 NULL,
466 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
467 );
468 if (EFI_ERROR (Status)) {
469 return EFI_INVALID_PARAMETER;
470 }
471
472 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
473
474 NotifyList = &TerminalDevice->NotifyList;
475 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
476 CurrentNotify = CR (
477 Link,
478 TERMINAL_CONSOLE_IN_EX_NOTIFY,
479 NotifyEntry,
480 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
481 );
482 if (CurrentNotify->NotifyHandle == NotificationHandle) {
483 //
484 // Remove the notification function from NotifyList and free resources
485 //
486 RemoveEntryList (&CurrentNotify->NotifyEntry);
487 Status = gBS->UninstallMultipleProtocolInterfaces (
488 CurrentNotify->NotifyHandle,
489 &gSimpleTextInExNotifyGuid,
490 NULL,
491 NULL
492 );
493 ASSERT_EFI_ERROR (Status);
494 gBS->FreePool (CurrentNotify);
495 return EFI_SUCCESS;
496 }
497 }
498
499 return EFI_NOT_FOUND;
500 }
501
502 /**
503 Translate raw data into Unicode (according to different encode), and
504 translate Unicode into key information. (according to different standard).
505
506 @param TerminalDevice Terminal driver private structure.
507
508 @return none.
509
510 **/
511 VOID
512 TranslateRawDataToEfiKey (
513 IN TERMINAL_DEV *TerminalDevice
514 )
515 {
516 switch (TerminalDevice->TerminalType) {
517
518 case PCANSITYPE:
519 case VT100TYPE:
520 case VT100PLUSTYPE:
521 AnsiRawDataToUnicode (TerminalDevice);
522 UnicodeToEfiKey (TerminalDevice);
523 break;
524
525 case VTUTF8TYPE:
526 //
527 // Process all the raw data in the RawFIFO,
528 // put the processed key into UnicodeFIFO.
529 //
530 VTUTF8RawDataToUnicode (TerminalDevice);
531
532 //
533 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
534 // then put into EfiKeyFIFO.
535 //
536 UnicodeToEfiKey (TerminalDevice);
537
538 break;
539 }
540 }
541
542 /**
543 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
544 Signal the event if there is key available
545
546 @param Event Indicates the event that invoke this function.
547 @param Context Indicates the calling context.
548
549 @return None
550
551 **/
552 VOID
553 EFIAPI
554 TerminalConInWaitForKey (
555 IN EFI_EVENT Event,
556 IN VOID *Context
557 )
558 {
559 //
560 // Someone is waiting on the keystroke event, if there's
561 // a key pending, signal the event
562 //
563 // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
564 //
565 if (!EFI_ERROR (TerminalConInCheckForKey (Context))) {
566
567 gBS->SignalEvent (Event);
568 }
569 }
570
571
572 /**
573 Check for a pending key in the Efi Key FIFO or Serial device buffer.
574
575 @param This Indicates the calling context.
576
577 @retval EFI_SUCCESS There is key pending.
578 @retval EFI_NOT_READY There is no key pending.
579 @retval EFI_DEVICE_ERROR If Serial IO is not attached to serial device.
580
581 **/
582 EFI_STATUS
583 TerminalConInCheckForKey (
584 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
585 )
586 {
587 EFI_STATUS Status;
588 TERMINAL_DEV *TerminalDevice;
589 UINT32 Control;
590 UINT8 Input;
591 EFI_SERIAL_IO_MODE *Mode;
592 EFI_SERIAL_IO_PROTOCOL *SerialIo;
593 UINTN SerialInTimeOut;
594
595 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
596
597 SerialIo = TerminalDevice->SerialIo;
598 if (SerialIo == NULL) {
599 return EFI_DEVICE_ERROR;
600 }
601 //
602 // if current timeout value for serial device is not identical with
603 // the value saved in TERMINAL_DEV structure, then recalculate the
604 // timeout value again and set serial attribute according to this value.
605 //
606 Mode = SerialIo->Mode;
607 if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
608
609 SerialInTimeOut = 0;
610 if (Mode->BaudRate != 0) {
611 //
612 // According to BAUD rate to calculate the timeout value.
613 //
614 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
615 }
616
617 Status = SerialIo->SetAttributes (
618 SerialIo,
619 Mode->BaudRate,
620 Mode->ReceiveFifoDepth,
621 (UINT32) SerialInTimeOut,
622 (EFI_PARITY_TYPE) (Mode->Parity),
623 (UINT8) Mode->DataBits,
624 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
625 );
626
627 if (EFI_ERROR (Status)) {
628 TerminalDevice->SerialInTimeOut = 0;
629 } else {
630 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
631 }
632 }
633 //
634 // Check whether serial buffer is empty.
635 //
636 Status = SerialIo->GetControl (SerialIo, &Control);
637
638 if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) != 0) {
639 //
640 // Translate all the raw data in RawFIFO into EFI Key,
641 // according to different terminal type supported.
642 //
643 TranslateRawDataToEfiKey (TerminalDevice);
644
645 //
646 // if there is pre-fetched Efi Key in EfiKeyFIFO buffer,
647 // return directly.
648 //
649 if (!IsEfiKeyFiFoEmpty (TerminalDevice)) {
650 return EFI_SUCCESS;
651 } else {
652 return EFI_NOT_READY;
653 }
654 }
655 //
656 // Fetch all the keys in the serial buffer,
657 // and insert the byte stream into RawFIFO.
658 //
659 do {
660
661 Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
662
663 if (EFI_ERROR (Status)) {
664 if (Status == EFI_DEVICE_ERROR) {
665 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
666 EFI_ERROR_CODE | EFI_ERROR_MINOR,
667 PcdGet32 (PcdStatusCodeValueRemoteConsoleInputError),
668 TerminalDevice->DevicePath
669 );
670 }
671 break;
672 }
673
674 RawFiFoInsertOneKey (TerminalDevice, Input);
675 } while (TRUE);
676
677 //
678 // Translate all the raw data in RawFIFO into EFI Key,
679 // according to different terminal type supported.
680 //
681 TranslateRawDataToEfiKey (TerminalDevice);
682
683 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
684 return EFI_NOT_READY;
685 }
686
687 return EFI_SUCCESS;
688 }
689
690 /**
691 Get one key out of serial buffer.
692
693 @param SerialIo Serial I/O protocol attached to the serial device.
694 @param Output The fetched key.
695
696 @return EFI_NOT_READY If serial buffer is empty.
697 @return EFI_DEVICE_ERROR If reading serial buffer encounter error.
698 @return EFI_SUCCESS If reading serial buffer successfully, put
699 the fetched key to the parameter output.
700
701 **/
702 EFI_STATUS
703 GetOneKeyFromSerial (
704 EFI_SERIAL_IO_PROTOCOL *SerialIo,
705 UINT8 *Output
706 )
707 {
708 EFI_STATUS Status;
709 UINTN Size;
710
711 Size = 1;
712 *Output = 0;
713
714 //
715 // Read one key from serial I/O device.
716 //
717 Status = SerialIo->Read (SerialIo, &Size, Output);
718
719 if (EFI_ERROR (Status)) {
720
721 if (Status == EFI_TIMEOUT) {
722 return EFI_NOT_READY;
723 }
724
725 return EFI_DEVICE_ERROR;
726
727 }
728
729 if (*Output == 0) {
730 return EFI_NOT_READY;
731 }
732
733 return EFI_SUCCESS;
734 }
735
736 /**
737 Insert one byte raw data into the Raw Data FIFO.
738
739 @param TerminalDevice Terminal driver private structure.
740 @param Input The key will be input.
741
742 @return TRUE If insert successfully.
743 @return FLASE If Raw Data buffer is full before key insertion,
744 and the key is lost.
745
746 **/
747 BOOLEAN
748 RawFiFoInsertOneKey (
749 TERMINAL_DEV *TerminalDevice,
750 UINT8 Input
751 )
752 {
753 UINT8 Tail;
754
755 Tail = TerminalDevice->RawFiFo.Tail;
756
757 if (IsRawFiFoFull (TerminalDevice)) {
758 //
759 // Raw FIFO is full
760 //
761 return FALSE;
762 }
763
764 TerminalDevice->RawFiFo.Data[Tail] = Input;
765
766 TerminalDevice->RawFiFo.Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
767
768 return TRUE;
769 }
770
771 /**
772 Remove one pre-fetched key out of the Raw Data FIFO.
773
774 @param TerminalDevice Terminal driver private structure.
775 @param Output The key will be removed.
776
777 @return TRUE If insert successfully.
778 @return FLASE If Raw Data FIFO buffer is empty before remove operation.
779
780 **/
781 BOOLEAN
782 RawFiFoRemoveOneKey (
783 TERMINAL_DEV *TerminalDevice,
784 UINT8 *Output
785 )
786 {
787 UINT8 Head;
788
789 Head = TerminalDevice->RawFiFo.Head;
790
791 if (IsRawFiFoEmpty (TerminalDevice)) {
792 //
793 // FIFO is empty
794 //
795 *Output = 0;
796 return FALSE;
797 }
798
799 *Output = TerminalDevice->RawFiFo.Data[Head];
800
801 TerminalDevice->RawFiFo.Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
802
803 return TRUE;
804 }
805
806 /**
807 Clarify whether Raw Data FIFO buffer is empty.
808
809 @param TerminalDevice Terminal driver private structure
810
811 @return TRUE If Raw Data FIFO buffer is empty.
812 @return FLASE If Raw Data FIFO buffer is not empty.
813
814 **/
815 BOOLEAN
816 IsRawFiFoEmpty (
817 TERMINAL_DEV *TerminalDevice
818 )
819 {
820 if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) {
821 return TRUE;
822 } else {
823 return FALSE;
824 }
825 }
826
827 /**
828 Clarify whether Raw Data FIFO buffer is full.
829
830 @param TerminalDevice Terminal driver private structure
831
832 @return TRUE If Raw Data FIFO buffer is full.
833 @return FLASE If Raw Data FIFO buffer is not full.
834
835 **/
836 BOOLEAN
837 IsRawFiFoFull (
838 TERMINAL_DEV *TerminalDevice
839 )
840 {
841 UINT8 Tail;
842 UINT8 Head;
843
844 Tail = TerminalDevice->RawFiFo.Tail;
845 Head = TerminalDevice->RawFiFo.Head;
846
847 if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
848
849 return TRUE;
850 }
851
852 return FALSE;
853 }
854
855 /**
856 Insert one pre-fetched key into the FIFO buffer.
857
858 @param TerminalDevice Terminal driver private structure.
859 @param Key The key will be input.
860
861 @return TRUE If insert successfully.
862 @return FLASE If FIFO buffer is full before key insertion,
863 and the key is lost.
864
865 **/
866 BOOLEAN
867 EfiKeyFiFoInsertOneKey (
868 TERMINAL_DEV *TerminalDevice,
869 EFI_INPUT_KEY Key
870 )
871 {
872 UINT8 Tail;
873
874 Tail = TerminalDevice->EfiKeyFiFo.Tail;
875
876 if (IsEfiKeyFiFoFull (TerminalDevice)) {
877 //
878 // Efi Key FIFO is full
879 //
880 return FALSE;
881 }
882
883 TerminalDevice->EfiKeyFiFo.Data[Tail] = Key;
884
885 TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
886
887 return TRUE;
888 }
889
890 /**
891 Remove one pre-fetched key out of the FIFO buffer.
892
893 @param TerminalDevice Terminal driver private structure.
894 @param Output The key will be removed.
895
896 @return TRUE If insert successfully.
897 @return FLASE If FIFO buffer is empty before remove operation.
898
899 **/
900 BOOLEAN
901 EfiKeyFiFoRemoveOneKey (
902 TERMINAL_DEV *TerminalDevice,
903 EFI_INPUT_KEY *Output
904 )
905 {
906 UINT8 Head;
907
908 Head = TerminalDevice->EfiKeyFiFo.Head;
909
910 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
911 //
912 // FIFO is empty
913 //
914 Output->ScanCode = SCAN_NULL;
915 Output->UnicodeChar = 0;
916 return FALSE;
917 }
918
919 *Output = TerminalDevice->EfiKeyFiFo.Data[Head];
920
921 TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
922
923 return TRUE;
924 }
925
926 /**
927 Clarify whether FIFO buffer is empty.
928
929 @param TerminalDevice Terminal driver private structure
930
931 @return TRUE If FIFO buffer is empty.
932 @return FLASE If FIFO buffer is not empty.
933
934 **/
935 BOOLEAN
936 IsEfiKeyFiFoEmpty (
937 TERMINAL_DEV *TerminalDevice
938 )
939 {
940 if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) {
941 return TRUE;
942 } else {
943 return FALSE;
944 }
945 }
946
947 /**
948 Clarify whether FIFO buffer is full.
949
950 @param TerminalDevice Terminal driver private structure
951
952 @return TRUE If FIFO buffer is full.
953 @return FLASE If FIFO buffer is not full.
954
955 **/
956 BOOLEAN
957 IsEfiKeyFiFoFull (
958 TERMINAL_DEV *TerminalDevice
959 )
960 {
961 UINT8 Tail;
962 UINT8 Head;
963
964 Tail = TerminalDevice->EfiKeyFiFo.Tail;
965 Head = TerminalDevice->EfiKeyFiFo.Head;
966
967 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
968
969 return TRUE;
970 }
971
972 return FALSE;
973 }
974
975 /**
976 Insert one pre-fetched key into the Unicode FIFO buffer.
977
978 @param TerminalDevice Terminal driver private structure.
979 @param Input The key will be input.
980
981 @return TRUE If insert successfully.
982 @return FLASE If Unicode FIFO buffer is full before key insertion,
983 and the key is lost.
984
985 **/
986 BOOLEAN
987 UnicodeFiFoInsertOneKey (
988 TERMINAL_DEV *TerminalDevice,
989 UINT16 Input
990 )
991 {
992 UINT8 Tail;
993
994 Tail = TerminalDevice->UnicodeFiFo.Tail;
995
996 if (IsUnicodeFiFoFull (TerminalDevice)) {
997 //
998 // Unicode FIFO is full
999 //
1000 return FALSE;
1001 }
1002
1003 TerminalDevice->UnicodeFiFo.Data[Tail] = Input;
1004
1005 TerminalDevice->UnicodeFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
1006
1007 return TRUE;
1008 }
1009
1010 /**
1011 Remove one pre-fetched key out of the Unicode FIFO buffer.
1012
1013 @param TerminalDevice Terminal driver private structure.
1014 @param Output The key will be removed.
1015
1016 @return TRUE If insert successfully.
1017 @return FLASE If Unicode FIFO buffer is empty before remove operation.
1018
1019 **/
1020 BOOLEAN
1021 UnicodeFiFoRemoveOneKey (
1022 TERMINAL_DEV *TerminalDevice,
1023 UINT16 *Output
1024 )
1025 {
1026 UINT8 Head;
1027
1028 Head = TerminalDevice->UnicodeFiFo.Head;
1029
1030 if (IsUnicodeFiFoEmpty (TerminalDevice)) {
1031 //
1032 // FIFO is empty
1033 //
1034 Output = NULL;
1035 return FALSE;
1036 }
1037
1038 *Output = TerminalDevice->UnicodeFiFo.Data[Head];
1039
1040 TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
1041
1042 return TRUE;
1043 }
1044
1045 /**
1046 Clarify whether Unicode FIFO buffer is empty.
1047
1048 @param TerminalDevice Terminal driver private structure
1049
1050 @return TRUE If Unicode FIFO buffer is empty.
1051 @return FLASE If Unicode FIFO buffer is not empty.
1052
1053 **/
1054 BOOLEAN
1055 IsUnicodeFiFoEmpty (
1056 TERMINAL_DEV *TerminalDevice
1057 )
1058 {
1059 if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) {
1060 return TRUE;
1061 } else {
1062 return FALSE;
1063 }
1064 }
1065
1066 /**
1067 Clarify whether Unicode FIFO buffer is full.
1068
1069 @param TerminalDevice Terminal driver private structure
1070
1071 @return TRUE If Unicode FIFO buffer is full.
1072 @return FLASE If Unicode FIFO buffer is not full.
1073
1074 **/
1075 BOOLEAN
1076 IsUnicodeFiFoFull (
1077 TERMINAL_DEV *TerminalDevice
1078 )
1079 {
1080 UINT8 Tail;
1081 UINT8 Head;
1082
1083 Tail = TerminalDevice->UnicodeFiFo.Tail;
1084 Head = TerminalDevice->UnicodeFiFo.Head;
1085
1086 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
1087
1088 return TRUE;
1089 }
1090
1091 return FALSE;
1092 }
1093
1094 /**
1095 Count Unicode FIFO buffer.
1096
1097 @param TerminalDevice Terminal driver private structure
1098
1099 @return The count in bytes of Unicode FIFO.
1100
1101 **/
1102 UINT8
1103 UnicodeFiFoGetKeyCount (
1104 TERMINAL_DEV *TerminalDevice
1105 )
1106 {
1107 UINT8 Tail;
1108 UINT8 Head;
1109
1110 Tail = TerminalDevice->UnicodeFiFo.Tail;
1111 Head = TerminalDevice->UnicodeFiFo.Head;
1112
1113 if (Tail >= Head) {
1114 return (UINT8) (Tail - Head);
1115 } else {
1116 return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
1117 }
1118 }
1119
1120 /**
1121 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1122
1123 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1124
1125 @return None.
1126
1127 **/
1128 VOID
1129 UnicodeToEfiKeyFlushState (
1130 IN TERMINAL_DEV *TerminalDevice
1131 )
1132 {
1133 EFI_INPUT_KEY Key;
1134 UINT32 InputState;
1135
1136 InputState = TerminalDevice->InputState;
1137
1138 if ((InputState & INPUT_STATE_ESC) != 0) {
1139 Key.ScanCode = SCAN_ESC;
1140 Key.UnicodeChar = 0;
1141 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
1142 }
1143
1144 if ((InputState & INPUT_STATE_CSI) != 0) {
1145 Key.ScanCode = SCAN_NULL;
1146 Key.UnicodeChar = CSI;
1147 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
1148 }
1149
1150 if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
1151 Key.ScanCode = SCAN_NULL;
1152 Key.UnicodeChar = LEFTOPENBRACKET;
1153 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
1154 }
1155
1156 if ((InputState & INPUT_STATE_O) != 0) {
1157 Key.ScanCode = SCAN_NULL;
1158 Key.UnicodeChar = 'O';
1159 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
1160 }
1161
1162 if ((InputState & INPUT_STATE_2) != 0) {
1163 Key.ScanCode = SCAN_NULL;
1164 Key.UnicodeChar = '2';
1165 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
1166 }
1167
1168 //
1169 // Cancel the timer.
1170 //
1171 gBS->SetTimer (
1172 TerminalDevice->TwoSecondTimeOut,
1173 TimerCancel,
1174 0
1175 );
1176
1177 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1178 }
1179
1180
1181 /**
1182 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1183 can be read through the Simple Input Protocol.
1184
1185 The table below shows the keyboard input mappings that this function supports.
1186 If the ESC sequence listed in one of the columns is presented, then it is translated
1187 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1188 key strokes are converted into EFI Keys.
1189
1190 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1191 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1192 converted into EFI Keys.
1193 There is one special input sequence that will force the system to reset.
1194 This is ESC R ESC r ESC R.
1195
1196 Symbols used in table below
1197 ===========================
1198 ESC = 0x1B
1199 CSI = 0x9B
1200 DEL = 0x7f
1201 ^ = CTRL
1202
1203 +=========+======+===========+==========+==========+
1204 | | EFI | UEFI 2.0 | | |
1205 | | Scan | | VT100+ | |
1206 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1207 +=========+======+===========+==========+==========+
1208 | NULL | 0x00 | | | |
1209 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1210 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1211 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1212 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1213 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1214 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1215 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1216 | | | ESC [ L | | ESC [ L |
1217 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1218 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1219 | | | | | ESC [ ? |
1220 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1221 | | | | | ESC [ / |
1222 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1223 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1224 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1225 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1226 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1227 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1228 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1229 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1230 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1231 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1232 | Escape | 0x17 | ESC | ESC | ESC |
1233 | F11 | 0x15 | | ESC ! | |
1234 | F12 | 0x16 | | ESC @ | |
1235 +=========+======+===========+==========+==========+
1236
1237 Special Mappings
1238 ================
1239 ESC R ESC r ESC R = Reset System
1240
1241 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1242
1243 @return None.
1244
1245 **/
1246 VOID
1247 UnicodeToEfiKey (
1248 IN TERMINAL_DEV *TerminalDevice
1249 )
1250 {
1251 EFI_STATUS Status;
1252 EFI_STATUS TimerStatus;
1253 UINT16 UnicodeChar;
1254 EFI_INPUT_KEY Key;
1255 BOOLEAN SetDefaultResetState;
1256
1257 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1258
1259 if (!EFI_ERROR (TimerStatus)) {
1260 UnicodeToEfiKeyFlushState (TerminalDevice);
1261 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1262 }
1263
1264 while (!IsUnicodeFiFoEmpty(TerminalDevice)) {
1265
1266 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1267 //
1268 // Check to see if the 2 second timer has expired
1269 //
1270 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1271 if (!EFI_ERROR (TimerStatus)) {
1272 UnicodeToEfiKeyFlushState (TerminalDevice);
1273 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1274 }
1275 }
1276
1277 //
1278 // Fetch one Unicode character from the Unicode FIFO
1279 //
1280 UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
1281
1282 SetDefaultResetState = TRUE;
1283
1284 switch (TerminalDevice->InputState) {
1285 case INPUT_STATE_DEFAULT:
1286
1287 break;
1288
1289 case INPUT_STATE_ESC:
1290
1291 if (UnicodeChar == LEFTOPENBRACKET) {
1292 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
1293 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1294 continue;
1295 }
1296
1297 if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
1298 TerminalDevice->InputState |= INPUT_STATE_O;
1299 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1300 continue;
1301 }
1302
1303 Key.ScanCode = SCAN_NULL;
1304
1305 if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
1306 TerminalDevice->TerminalType == VTUTF8TYPE) {
1307 switch (UnicodeChar) {
1308 case '1':
1309 Key.ScanCode = SCAN_F1;
1310 break;
1311 case '2':
1312 Key.ScanCode = SCAN_F2;
1313 break;
1314 case '3':
1315 Key.ScanCode = SCAN_F3;
1316 break;
1317 case '4':
1318 Key.ScanCode = SCAN_F4;
1319 break;
1320 case '5':
1321 Key.ScanCode = SCAN_F5;
1322 break;
1323 case '6':
1324 Key.ScanCode = SCAN_F6;
1325 break;
1326 case '7':
1327 Key.ScanCode = SCAN_F7;
1328 break;
1329 case '8':
1330 Key.ScanCode = SCAN_F8;
1331 break;
1332 case '9':
1333 Key.ScanCode = SCAN_F9;
1334 break;
1335 case '0':
1336 Key.ScanCode = SCAN_F10;
1337 break;
1338 case '!':
1339 Key.ScanCode = SCAN_F11;
1340 break;
1341 case '@':
1342 Key.ScanCode = SCAN_F12;
1343 break;
1344 case 'h':
1345 Key.ScanCode = SCAN_HOME;
1346 break;
1347 case 'k':
1348 Key.ScanCode = SCAN_END;
1349 break;
1350 case '+':
1351 Key.ScanCode = SCAN_INSERT;
1352 break;
1353 case '-':
1354 Key.ScanCode = SCAN_DELETE;
1355 break;
1356 case '/':
1357 Key.ScanCode = SCAN_PAGE_DOWN;
1358 break;
1359 case '?':
1360 Key.ScanCode = SCAN_PAGE_UP;
1361 break;
1362 default :
1363 break;
1364 }
1365 }
1366
1367 switch (UnicodeChar) {
1368 case 'R':
1369 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
1370 TerminalDevice->ResetState = RESET_STATE_ESC_R;
1371 SetDefaultResetState = FALSE;
1372 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {
1373 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1374 }
1375 Key.ScanCode = SCAN_NULL;
1376 break;
1377 case 'r':
1378 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
1379 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;
1380 SetDefaultResetState = FALSE;
1381 }
1382 Key.ScanCode = SCAN_NULL;
1383 break;
1384 default :
1385 break;
1386 }
1387
1388 if (SetDefaultResetState) {
1389 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1390 }
1391
1392 if (Key.ScanCode != SCAN_NULL) {
1393 Key.UnicodeChar = 0;
1394 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1395 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1396 UnicodeToEfiKeyFlushState (TerminalDevice);
1397 continue;
1398 }
1399
1400 UnicodeToEfiKeyFlushState (TerminalDevice);
1401
1402 break;
1403
1404 case INPUT_STATE_ESC | INPUT_STATE_O:
1405
1406 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1407
1408 Key.ScanCode = SCAN_NULL;
1409
1410 if (TerminalDevice->TerminalType == VT100TYPE) {
1411 switch (UnicodeChar) {
1412 case 'P':
1413 Key.ScanCode = SCAN_F1;
1414 break;
1415 case 'Q':
1416 Key.ScanCode = SCAN_F2;
1417 break;
1418 case 'w':
1419 Key.ScanCode = SCAN_F3;
1420 break;
1421 case 'x':
1422 Key.ScanCode = SCAN_F4;
1423 break;
1424 case 't':
1425 Key.ScanCode = SCAN_F5;
1426 break;
1427 case 'u':
1428 Key.ScanCode = SCAN_F6;
1429 break;
1430 case 'q':
1431 Key.ScanCode = SCAN_F7;
1432 break;
1433 case 'r':
1434 Key.ScanCode = SCAN_F8;
1435 break;
1436 case 'p':
1437 Key.ScanCode = SCAN_F9;
1438 break;
1439 case 'M':
1440 Key.ScanCode = SCAN_F10;
1441 break;
1442 default :
1443 break;
1444 }
1445 }
1446
1447 if (Key.ScanCode != SCAN_NULL) {
1448 Key.UnicodeChar = 0;
1449 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1450 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1451 UnicodeToEfiKeyFlushState (TerminalDevice);
1452 continue;
1453 }
1454
1455 UnicodeToEfiKeyFlushState (TerminalDevice);
1456
1457 break;
1458
1459 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
1460
1461 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1462
1463 Key.ScanCode = SCAN_NULL;
1464
1465 if (TerminalDevice->TerminalType == PCANSITYPE ||
1466 TerminalDevice->TerminalType == VT100TYPE ||
1467 TerminalDevice->TerminalType == VT100PLUSTYPE ||
1468 TerminalDevice->TerminalType == VTUTF8TYPE) {
1469 switch (UnicodeChar) {
1470 case 'A':
1471 Key.ScanCode = SCAN_UP;
1472 break;
1473 case 'B':
1474 Key.ScanCode = SCAN_DOWN;
1475 break;
1476 case 'C':
1477 Key.ScanCode = SCAN_RIGHT;
1478 break;
1479 case 'D':
1480 Key.ScanCode = SCAN_LEFT;
1481 break;
1482 case 'H':
1483 if (TerminalDevice->TerminalType == PCANSITYPE ||
1484 TerminalDevice->TerminalType == VT100TYPE) {
1485 Key.ScanCode = SCAN_HOME;
1486 }
1487 break;
1488 case 'F':
1489 if (TerminalDevice->TerminalType == PCANSITYPE) {
1490 Key.ScanCode = SCAN_END;
1491 }
1492 break;
1493 case 'K':
1494 if (TerminalDevice->TerminalType == VT100TYPE) {
1495 Key.ScanCode = SCAN_END;
1496 }
1497 break;
1498 case 'L':
1499 case '@':
1500 if (TerminalDevice->TerminalType == PCANSITYPE ||
1501 TerminalDevice->TerminalType == VT100TYPE) {
1502 Key.ScanCode = SCAN_INSERT;
1503 }
1504 break;
1505 case 'X':
1506 if (TerminalDevice->TerminalType == PCANSITYPE) {
1507 Key.ScanCode = SCAN_DELETE;
1508 }
1509 break;
1510 case 'P':
1511 if (TerminalDevice->TerminalType == VT100TYPE) {
1512 Key.ScanCode = SCAN_DELETE;
1513 } else if (TerminalDevice->TerminalType == PCANSITYPE) {
1514 Key.ScanCode = SCAN_F4;
1515 }
1516 break;
1517 case 'I':
1518 if (TerminalDevice->TerminalType == PCANSITYPE) {
1519 Key.ScanCode = SCAN_PAGE_UP;
1520 }
1521 break;
1522 case 'V':
1523 if (TerminalDevice->TerminalType == PCANSITYPE) {
1524 Key.ScanCode = SCAN_F10;
1525 }
1526 case '?':
1527 if (TerminalDevice->TerminalType == VT100TYPE) {
1528 Key.ScanCode = SCAN_PAGE_UP;
1529 }
1530 break;
1531 case 'G':
1532 if (TerminalDevice->TerminalType == PCANSITYPE) {
1533 Key.ScanCode = SCAN_PAGE_DOWN;
1534 }
1535 break;
1536 case 'U':
1537 if (TerminalDevice->TerminalType == PCANSITYPE) {
1538 Key.ScanCode = SCAN_F9;
1539 }
1540 case '/':
1541 if (TerminalDevice->TerminalType == VT100TYPE) {
1542 Key.ScanCode = SCAN_PAGE_DOWN;
1543 }
1544 break;
1545 case 'M':
1546 if (TerminalDevice->TerminalType == PCANSITYPE) {
1547 Key.ScanCode = SCAN_F1;
1548 }
1549 break;
1550 case 'N':
1551 if (TerminalDevice->TerminalType == PCANSITYPE) {
1552 Key.ScanCode = SCAN_F2;
1553 }
1554 break;
1555 case 'O':
1556 if (TerminalDevice->TerminalType == PCANSITYPE) {
1557 Key.ScanCode = SCAN_F3;
1558 }
1559 break;
1560 case 'Q':
1561 if (TerminalDevice->TerminalType == PCANSITYPE) {
1562 Key.ScanCode = SCAN_F5;
1563 }
1564 break;
1565 case 'R':
1566 if (TerminalDevice->TerminalType == PCANSITYPE) {
1567 Key.ScanCode = SCAN_F6;
1568 }
1569 break;
1570 case 'S':
1571 if (TerminalDevice->TerminalType == PCANSITYPE) {
1572 Key.ScanCode = SCAN_F7;
1573 }
1574 break;
1575 case 'T':
1576 if (TerminalDevice->TerminalType == PCANSITYPE) {
1577 Key.ScanCode = SCAN_F8;
1578 }
1579 break;
1580 default :
1581 break;
1582 }
1583 }
1584
1585 if (Key.ScanCode != SCAN_NULL) {
1586 Key.UnicodeChar = 0;
1587 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1588 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1589 UnicodeToEfiKeyFlushState (TerminalDevice);
1590 continue;
1591 }
1592
1593 UnicodeToEfiKeyFlushState (TerminalDevice);
1594
1595 break;
1596
1597
1598 default:
1599 //
1600 // Invalid state. This should never happen.
1601 //
1602 ASSERT (FALSE);
1603
1604 UnicodeToEfiKeyFlushState (TerminalDevice);
1605
1606 break;
1607 }
1608
1609 if (UnicodeChar == ESC) {
1610 TerminalDevice->InputState = INPUT_STATE_ESC;
1611 }
1612
1613 if (UnicodeChar == CSI) {
1614 TerminalDevice->InputState = INPUT_STATE_CSI;
1615 }
1616
1617 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1618 Status = gBS->SetTimer(
1619 TerminalDevice->TwoSecondTimeOut,
1620 TimerRelative,
1621 (UINT64)20000000
1622 );
1623 ASSERT_EFI_ERROR (Status);
1624 continue;
1625 }
1626
1627 if (SetDefaultResetState) {
1628 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1629 }
1630
1631 if (UnicodeChar == DEL) {
1632 Key.ScanCode = SCAN_DELETE;
1633 Key.UnicodeChar = 0;
1634 } else {
1635 Key.ScanCode = SCAN_NULL;
1636 Key.UnicodeChar = UnicodeChar;
1637 }
1638
1639 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1640 }
1641 }