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