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