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