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