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