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