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