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