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