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