Remove the redundant include header: Common/StatusCode.h for Terminal modules.
[mirror_edk2.git] / EdkModulePkg / Universal / Console / Terminal / Dxe / TerminalConIn.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 TerminalConIn.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
878ddf1f 22#include "Terminal.h"\r
23\r
878ddf1f 24EFI_STATUS\r
25EFIAPI\r
26TerminalConInReset (\r
27 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,\r
28 IN BOOLEAN ExtendedVerification\r
29 )\r
30/*++\r
31 Routine Description:\r
32 \r
33 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset().\r
34 This driver only perform dependent serial device reset regardless of \r
35 the value of ExtendeVerification\r
36 \r
37 Arguments:\r
38 \r
39 This - Indicates the calling context.\r
40 \r
41 ExtendedVerification - Skip by this driver.\r
42 \r
43 Returns:\r
44 \r
45 EFI_SUCCESS\r
46 The reset operation succeeds. \r
47 \r
48 EFI_DEVICE_ERROR\r
49 The dependent serial port reset fails.\r
50 \r
51--*/\r
52{\r
53 EFI_STATUS Status;\r
54 TERMINAL_DEV *TerminalDevice;\r
55\r
56 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
57\r
58 //\r
59 // Report progress code here\r
60 //\r
61 Status = REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
62 EFI_PROGRESS_CODE,\r
63 EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET,\r
64 TerminalDevice->DevicePath\r
65 );\r
66\r
67 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);\r
68\r
69 //\r
70 // clear all the internal buffer for keys\r
71 //\r
72 InitializeRawFiFo (TerminalDevice);\r
73 InitializeUnicodeFiFo (TerminalDevice);\r
74 InitializeEfiKeyFiFo (TerminalDevice);\r
75\r
76 if (EFI_ERROR (Status)) {\r
77 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
78 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
79 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
80 TerminalDevice->DevicePath\r
81 );\r
82 }\r
83\r
84 return Status;\r
85}\r
86\r
87EFI_STATUS\r
88EFIAPI\r
89TerminalConInReadKeyStroke (\r
90 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,\r
91 OUT EFI_INPUT_KEY *Key\r
92 )\r
93/*++\r
94 Routine Description:\r
95 \r
96 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke().\r
97 \r
98 Arguments:\r
99 \r
100 This - Indicates the calling context.\r
101 \r
102 Key - A pointer to a buffer that is filled in with the keystroke\r
103 information for the key that was sent from terminal. \r
104 \r
105 Returns:\r
106 \r
107 EFI_SUCCESS\r
108 The keystroke information is returned successfully.\r
109 \r
110 EFI_NOT_READY\r
111 There is no keystroke data available.\r
112 \r
113 EFI_DEVICE_ERROR\r
114 The dependent serial device encounters error.\r
115 \r
116--*/\r
117{\r
118 TERMINAL_DEV *TerminalDevice;\r
119 EFI_STATUS Status;\r
120\r
121 //\r
122 // Initialize *Key to nonsense value.\r
123 //\r
124 Key->ScanCode = SCAN_NULL;\r
125 Key->UnicodeChar = 0;\r
126 //\r
127 // get TERMINAL_DEV from "This" parameter.\r
128 //\r
129 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
130\r
131 Status = TerminalConInCheckForKey (This);\r
132 if (EFI_ERROR (Status)) {\r
133 return EFI_NOT_READY;\r
134 }\r
135\r
136 EfiKeyFiFoRemoveOneKey (TerminalDevice, Key);\r
137\r
138 return EFI_SUCCESS;\r
139\r
140}\r
141\r
142VOID\r
143TranslateRawDataToEfiKey (\r
144 IN TERMINAL_DEV *TerminalDevice\r
145 )\r
146/*++\r
147 Step1: Turn raw data into Unicode (according to different encode).\r
148 Step2: Translate Unicode into key information. \r
149 (according to different terminal standard).\r
150--*/\r
151{\r
152 switch (TerminalDevice->TerminalType) {\r
153\r
154 case PcAnsiType:\r
155 case VT100Type:\r
156 case VT100PlusType:\r
157 AnsiRawDataToUnicode (TerminalDevice);\r
158 UnicodeToEfiKey (TerminalDevice);\r
159 break;\r
160\r
161 case VTUTF8Type:\r
162 //\r
163 // Process all the raw data in the RawFIFO,\r
164 // put the processed key into UnicodeFIFO.\r
165 //\r
166 VTUTF8RawDataToUnicode (TerminalDevice);\r
167\r
168 //\r
169 // Translate all the Unicode data in the UnicodeFIFO to Efi key,\r
170 // then put into EfiKeyFIFO.\r
171 //\r
172 UnicodeToEfiKey (TerminalDevice);\r
173\r
174 break;\r
175 }\r
176}\r
177\r
178VOID\r
179EFIAPI\r
180TerminalConInWaitForKey (\r
181 IN EFI_EVENT Event,\r
182 IN VOID *Context\r
183 )\r
184/*++\r
185 Routine Description:\r
186 \r
187 Event notification function for EFI_SIMPLE_TEXT_IN_PROTOCOL.WaitForKey event\r
188 Signal the event if there is key available \r
189 \r
190 Arguments:\r
191 \r
192 Event - Indicates the event that invoke this function.\r
193 \r
194 Context - Indicates the calling context.\r
195 \r
196 Returns:\r
197 \r
198 N/A\r
199 \r
200--*/\r
201{\r
202 //\r
203 // Someone is waiting on the keystroke event, if there's\r
204 // a key pending, signal the event\r
205 //\r
206 // Context is the pointer to EFI_SIMPLE_TEXT_IN_PROTOCOL\r
207 //\r
208 if (!EFI_ERROR (TerminalConInCheckForKey (Context))) {\r
209\r
210 gBS->SignalEvent (Event);\r
211 }\r
212}\r
213\r
214EFI_STATUS\r
215TerminalConInCheckForKey (\r
216 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This\r
217 )\r
218/*++\r
219 Routine Description:\r
220 \r
221 Check for a pending key in the Efi Key FIFO or Serial device buffer.\r
222 \r
223 Arguments:\r
224 \r
225 This - Indicates the calling context.\r
226 \r
227 Returns:\r
228 \r
229 EFI_SUCCESS\r
230 There is key pending. \r
231 \r
232 EFI_NOT_READY\r
233 There is no key pending.\r
234 \r
235 EFI_DEVICE_ERROR\r
236 \r
237--*/\r
238{\r
239 EFI_STATUS Status;\r
240 TERMINAL_DEV *TerminalDevice;\r
241 UINT32 Control;\r
242 UINT8 Input;\r
243 EFI_SERIAL_IO_MODE *Mode;\r
244 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
245 UINTN SerialInTimeOut;\r
246\r
247 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
248\r
249 SerialIo = TerminalDevice->SerialIo;\r
250 if (SerialIo == NULL) {\r
251 return EFI_DEVICE_ERROR;\r
252 }\r
253 //\r
254 // if current timeout value for serial device is not identical with\r
255 // the value saved in TERMINAL_DEV structure, then recalculate the\r
256 // timeout value again and set serial attribute according to this value.\r
257 //\r
258 Mode = SerialIo->Mode;\r
259 if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {\r
260\r
261 SerialInTimeOut = 0;\r
262 if (Mode->BaudRate != 0) {\r
263 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
264 }\r
265\r
266 Status = SerialIo->SetAttributes (\r
267 SerialIo,\r
268 Mode->BaudRate,\r
269 Mode->ReceiveFifoDepth,\r
270 (UINT32) SerialInTimeOut,\r
271 Mode->Parity,\r
272 (UINT8) Mode->DataBits,\r
273 Mode->StopBits\r
274 );\r
275\r
276 if (EFI_ERROR (Status)) {\r
277 TerminalDevice->SerialInTimeOut = 0;\r
278 } else {\r
279 TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
280 }\r
281 }\r
282 //\r
283 // check whether serial buffer is empty\r
284 //\r
285 Status = SerialIo->GetControl (SerialIo, &Control);\r
286\r
287 if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) {\r
288 //\r
289 // Translate all the raw data in RawFIFO into EFI Key,\r
290 // according to different terminal type supported.\r
291 //\r
292 TranslateRawDataToEfiKey (TerminalDevice);\r
293\r
294 //\r
295 // if there is pre-fetched Efi Key in EfiKeyFIFO buffer,\r
296 // return directly.\r
297 //\r
298 if (!IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
299 return EFI_SUCCESS;\r
300 } else {\r
301 return EFI_NOT_READY;\r
302 }\r
303 }\r
304 //\r
305 // Fetch all the keys in the serial buffer,\r
306 // and insert the byte stream into RawFIFO.\r
307 //\r
308 do {\r
309\r
310 Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);\r
311\r
312 if (EFI_ERROR (Status)) {\r
313 if (Status == EFI_DEVICE_ERROR) {\r
314 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
315 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
316 EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR,\r
317 TerminalDevice->DevicePath\r
318 );\r
319 }\r
320 break;\r
321 }\r
322\r
323 RawFiFoInsertOneKey (TerminalDevice, Input);\r
324 } while (TRUE);\r
325\r
326 //\r
327 // Translate all the raw data in RawFIFO into EFI Key,\r
328 // according to different terminal type supported.\r
329 //\r
330 TranslateRawDataToEfiKey (TerminalDevice);\r
331\r
332 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
333 return EFI_NOT_READY;\r
334 }\r
335\r
336 return EFI_SUCCESS;\r
337}\r
338\r
339EFI_STATUS\r
340GetOneKeyFromSerial (\r
341 EFI_SERIAL_IO_PROTOCOL *SerialIo,\r
342 UINT8 *Input\r
343 )\r
344/*++\r
345 Get one key out of serial buffer.\r
346 If serial buffer is empty, return EFI_NOT_READY;\r
347 if reading serial buffer encounter error, returns EFI_DEVICE_ERROR;\r
348 if reading serial buffer successfully, put the fetched key to \r
349 the parameter "Input", and return EFI_SUCCESS.\r
350--*/\r
351{\r
352 EFI_STATUS Status;\r
353 UINTN Size;\r
354\r
355 Size = 1;\r
356 *Input = 0;\r
357\r
358 Status = SerialIo->Read (SerialIo, &Size, Input);\r
359\r
360 if (EFI_ERROR (Status)) {\r
361\r
362 if (Status == EFI_TIMEOUT) {\r
363 return EFI_NOT_READY;\r
364 }\r
365\r
366 return EFI_DEVICE_ERROR;\r
367\r
368 }\r
369\r
370 if (*Input == 0) {\r
371 return EFI_NOT_READY;\r
372 }\r
373\r
374 return EFI_SUCCESS;\r
375}\r
376\r
377BOOLEAN\r
378RawFiFoInsertOneKey (\r
379 TERMINAL_DEV *TerminalDevice,\r
380 UINT8 Input\r
381 )\r
382/*++\r
383 Insert one byte raw data into the Raw Data FIFO.\r
384 If FIFO is FULL before data insertion,\r
385 return FALSE, and the key is lost.\r
386--*/\r
387{\r
388 UINT8 Tail;\r
389\r
390 Tail = TerminalDevice->RawFiFo.Tail;\r
391\r
392 if (IsRawFiFoFull (TerminalDevice)) {\r
393 //\r
394 // Raw FIFO is full\r
395 //\r
396 return FALSE;\r
397 }\r
398\r
399 TerminalDevice->RawFiFo.Data[Tail] = Input;\r
400\r
401 TerminalDevice->RawFiFo.Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
402\r
403 return TRUE;\r
404}\r
405\r
406BOOLEAN\r
407RawFiFoRemoveOneKey (\r
408 TERMINAL_DEV *TerminalDevice,\r
409 UINT8 *Output\r
410 )\r
411/*++\r
412 Remove one byte raw data out of the Raw Data FIFO.\r
413 If FIFO buffer is empty before remove operation,\r
414 return FALSE.\r
415--*/\r
416{\r
417 UINT8 Head;\r
418\r
419 Head = TerminalDevice->RawFiFo.Head;\r
420\r
421 if (IsRawFiFoEmpty (TerminalDevice)) {\r
422 //\r
423 // FIFO is empty\r
424 //\r
425 *Output = 0;\r
426 return FALSE;\r
427 }\r
428\r
429 *Output = TerminalDevice->RawFiFo.Data[Head];\r
430\r
431 TerminalDevice->RawFiFo.Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
432\r
433 return TRUE;\r
434}\r
435\r
436BOOLEAN\r
437IsRawFiFoEmpty (\r
438 TERMINAL_DEV *TerminalDevice\r
439 )\r
440/*++\r
441 Clarify whether FIFO buffer is empty.\r
442--*/\r
443{\r
444 if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) {\r
445 return TRUE;\r
446 } else {\r
447 return FALSE;\r
448 }\r
449}\r
450\r
451BOOLEAN\r
452IsRawFiFoFull (\r
453 TERMINAL_DEV *TerminalDevice\r
454 )\r
455/*++\r
456 Clarify whether FIFO buffer is full.\r
457--*/\r
458{\r
459 UINT8 Tail;\r
460 UINT8 Head;\r
461\r
462 Tail = TerminalDevice->RawFiFo.Tail;\r
463 Head = TerminalDevice->RawFiFo.Head;\r
464\r
465 if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {\r
466\r
467 return TRUE;\r
468 }\r
469\r
470 return FALSE;\r
471}\r
472\r
473BOOLEAN\r
474EfiKeyFiFoInsertOneKey (\r
475 TERMINAL_DEV *TerminalDevice,\r
476 EFI_INPUT_KEY Key\r
477 )\r
478/*++\r
479 Insert one pre-fetched key into the FIFO buffer.\r
480 If FIFO buffer is FULL before key insertion,\r
481 return FALSE, and the key is lost.\r
482--*/\r
483{\r
484 UINT8 Tail;\r
485\r
486 Tail = TerminalDevice->EfiKeyFiFo.Tail;\r
487\r
488 if (IsEfiKeyFiFoFull (TerminalDevice)) {\r
489 //\r
490 // Efi Key FIFO is full\r
491 //\r
492 return FALSE;\r
493 }\r
494\r
495 TerminalDevice->EfiKeyFiFo.Data[Tail] = Key;\r
496\r
497 TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
498\r
499 return TRUE;\r
500}\r
501\r
502BOOLEAN\r
503EfiKeyFiFoRemoveOneKey (\r
504 TERMINAL_DEV *TerminalDevice,\r
505 EFI_INPUT_KEY *Output\r
506 )\r
507/*++\r
508 Remove one pre-fetched key out of the FIFO buffer.\r
509 If FIFO buffer is empty before remove operation,\r
510 return FALSE.\r
511--*/\r
512{\r
513 UINT8 Head;\r
514\r
515 Head = TerminalDevice->EfiKeyFiFo.Head;\r
516\r
517 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
518 //\r
519 // FIFO is empty\r
520 //\r
521 Output->ScanCode = SCAN_NULL;\r
522 Output->UnicodeChar = 0;\r
523 return FALSE;\r
524 }\r
525\r
526 *Output = TerminalDevice->EfiKeyFiFo.Data[Head];\r
527\r
528 TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
529\r
530 return TRUE;\r
531}\r
532\r
533BOOLEAN\r
534IsEfiKeyFiFoEmpty (\r
535 TERMINAL_DEV *TerminalDevice\r
536 )\r
537/*++\r
538 Clarify whether FIFO buffer is empty.\r
539--*/\r
540{\r
541 if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) {\r
542 return TRUE;\r
543 } else {\r
544 return FALSE;\r
545 }\r
546}\r
547\r
548BOOLEAN\r
549IsEfiKeyFiFoFull (\r
550 TERMINAL_DEV *TerminalDevice\r
551 )\r
552/*++\r
553 Clarify whether FIFO buffer is full.\r
554--*/\r
555{\r
556 UINT8 Tail;\r
557 UINT8 Head;\r
558\r
559 Tail = TerminalDevice->EfiKeyFiFo.Tail;\r
560 Head = TerminalDevice->EfiKeyFiFo.Head;\r
561\r
562 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
563\r
564 return TRUE;\r
565 }\r
566\r
567 return FALSE;\r
568}\r
569\r
570BOOLEAN\r
571UnicodeFiFoInsertOneKey (\r
572 TERMINAL_DEV *TerminalDevice,\r
573 UINT16 Input\r
574 )\r
575/*++\r
576 Insert one pre-fetched key into the FIFO buffer.\r
577 If FIFO buffer is FULL before key insertion,\r
578 return FALSE, and the key is lost.\r
579--*/\r
580{\r
581 UINT8 Tail;\r
582\r
583 Tail = TerminalDevice->UnicodeFiFo.Tail;\r
584\r
585 if (IsUnicodeFiFoFull (TerminalDevice)) {\r
586 //\r
587 // Unicode FIFO is full\r
588 //\r
589 return FALSE;\r
590 }\r
591\r
592 TerminalDevice->UnicodeFiFo.Data[Tail] = Input;\r
593\r
594 TerminalDevice->UnicodeFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
595\r
596 return TRUE;\r
597}\r
598\r
599BOOLEAN\r
600UnicodeFiFoRemoveOneKey (\r
601 TERMINAL_DEV *TerminalDevice,\r
602 UINT16 *Output\r
603 )\r
604/*++\r
605 Remove one pre-fetched key out of the FIFO buffer.\r
606 If FIFO buffer is empty before remove operation,\r
607 return FALSE.\r
608--*/\r
609{\r
610 UINT8 Head;\r
611\r
612 Head = TerminalDevice->UnicodeFiFo.Head;\r
613\r
614 if (IsUnicodeFiFoEmpty (TerminalDevice)) {\r
615 //\r
616 // FIFO is empty\r
617 //\r
618 Output = NULL;\r
619 return FALSE;\r
620 }\r
621\r
622 *Output = TerminalDevice->UnicodeFiFo.Data[Head];\r
623\r
624 TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
625\r
626 return TRUE;\r
627}\r
628\r
629BOOLEAN\r
630IsUnicodeFiFoEmpty (\r
631 TERMINAL_DEV *TerminalDevice\r
632 )\r
633/*++\r
634 Clarify whether FIFO buffer is empty.\r
635--*/\r
636{\r
637 if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) {\r
638 return TRUE;\r
639 } else {\r
640 return FALSE;\r
641 }\r
642}\r
643\r
644BOOLEAN\r
645IsUnicodeFiFoFull (\r
646 TERMINAL_DEV *TerminalDevice\r
647 )\r
648/*++\r
649 Clarify whether FIFO buffer is full.\r
650--*/\r
651{\r
652 UINT8 Tail;\r
653 UINT8 Head;\r
654\r
655 Tail = TerminalDevice->UnicodeFiFo.Tail;\r
656 Head = TerminalDevice->UnicodeFiFo.Head;\r
657\r
658 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
659\r
660 return TRUE;\r
661 }\r
662\r
663 return FALSE;\r
664}\r
665\r
666UINT8\r
667UnicodeFiFoGetKeyCount (\r
668 TERMINAL_DEV *TerminalDevice\r
669 )\r
670{\r
671 UINT8 Tail;\r
672 UINT8 Head;\r
673\r
674 Tail = TerminalDevice->UnicodeFiFo.Tail;\r
675 Head = TerminalDevice->UnicodeFiFo.Head;\r
676\r
677 if (Tail >= Head) {\r
678 return (UINT8) (Tail - Head);\r
679 } else {\r
680 return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);\r
681 }\r
682}\r
683\r
684VOID\r
685UnicodeToEfiKeyFlushState (\r
686 IN TERMINAL_DEV *TerminalDevice\r
687 )\r
688{\r
689 EFI_INPUT_KEY Key;\r
690\r
691 if (TerminalDevice->InputState & INPUT_STATE_ESC) {\r
692 Key.ScanCode = SCAN_ESC;\r
693 Key.UnicodeChar = 0;\r
694 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
695 }\r
696\r
697 if (TerminalDevice->InputState & INPUT_STATE_CSI) {\r
698 Key.ScanCode = SCAN_NULL;\r
699 Key.UnicodeChar = CSI;\r
700 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
701 }\r
702\r
703 if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) {\r
704 Key.ScanCode = SCAN_NULL;\r
705 Key.UnicodeChar = LEFTOPENBRACKET;\r
706 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
707 }\r
708\r
709 if (TerminalDevice->InputState & INPUT_STATE_O) {\r
710 Key.ScanCode = SCAN_NULL;\r
711 Key.UnicodeChar = 'O';\r
712 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
713 }\r
714\r
715 if (TerminalDevice->InputState & INPUT_STATE_2) {\r
716 Key.ScanCode = SCAN_NULL;\r
717 Key.UnicodeChar = '2';\r
718 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
719 }\r
720\r
721 gBS->SetTimer (\r
722 TerminalDevice->TwoSecondTimeOut,\r
723 TimerCancel,\r
724 0\r
725 );\r
726\r
727 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
728}\r
729\r
730VOID\r
731UnicodeToEfiKey (\r
732 IN TERMINAL_DEV *TerminalDevice\r
733 )\r
734/*++\r
735 Routine Description:\r
736 \r
737 Converts a stream of Unicode characters from a terminal input device into EFI Keys that\r
738 can be read through the Simple Input Protocol. The table below shows the keyboard\r
739 input mappings that this function supports. If the ESC sequence listed in one of the \r
740 columns is presented, then it is translated into the coorespoding EFI Scan Code. If a\r
741 matching sequence is not found, then the raw key strokes are converted into EFI Keys.\r
742 \r
743 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not \r
744 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are \r
745 converted into EFI Keys.\r
746 \r
747 There is one special input sequence that will force the system to reset. \r
748 This is ESC R ESC r ESC R.\r
749 \r
750 Arguments:\r
751\r
752 TerminaDevice : The terminal device to use to translate raw input into EFI Keys\r
753 \r
754 Returns:\r
755\r
756 None\r
757\r
758Symbols used in table below\r
759===========================\r
760 ESC = 0x1B \r
761 CSI = 0x9B \r
762 DEL = 0x7f \r
763 ^ = CTRL\r
764\r
765+=========+======+===========+==========+==========+\r
766| | EFI | EFI 1.10 | | |\r
767| | Scan | | VT100+ | |\r
768| KEY | Code | PC ANSI | VTUTF8 | VT100 |\r
769+=========+======+===========+==========+==========+\r
770| NULL | 0x00 | | | |\r
771| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |\r
772| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |\r
773| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | \r
774| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |\r
775| HOME | 0x05 | ESC [ H | ESC h | ESC [ H |\r
776| END | 0x06 | ESC [ F | ESC k | ESC [ K |\r
777| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |\r
778| | | ESC [ L | | ESC [ L |\r
779| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |\r
780| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |\r
781| | | | | ESC [ ? |\r
782| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |\r
783| | | | | ESC [ / |\r
784| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |\r
785| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |\r
786| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |\r
787| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |\r
788| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |\r
789| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |\r
790| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |\r
791| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |\r
792| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |\r
793| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |\r
794| Escape | 0x17 | ESC | ESC | ESC |\r
795+=========+======+===========+==========+=========+\r
796\r
797Special Mappings\r
798================\r
799ESC R ESC r ESC R = Reset System\r
800\r
801--*/\r
802{\r
803 EFI_STATUS Status;\r
804 EFI_STATUS TimerStatus;\r
805 UINT16 UnicodeChar;\r
806 EFI_INPUT_KEY Key;\r
807 BOOLEAN SetDefaultResetState;\r
808 \r
809 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
810\r
811 if (!EFI_ERROR (TimerStatus)) {\r
812 UnicodeToEfiKeyFlushState (TerminalDevice);\r
813 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
814 }\r
815\r
816 while (!IsUnicodeFiFoEmpty(TerminalDevice)) {\r
817 \r
818 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
819 //\r
820 // Check to see if the 2 second timer has expired\r
821 //\r
822 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
823 if (!EFI_ERROR (TimerStatus)) {\r
824 UnicodeToEfiKeyFlushState (TerminalDevice);\r
825 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
826 }\r
827 }\r
828\r
829 //\r
830 // Fetch one Unicode character from the Unicode FIFO\r
831 //\r
832 UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar);\r
833\r
834 SetDefaultResetState = TRUE;\r
835\r
836 switch (TerminalDevice->InputState) {\r
837 case INPUT_STATE_DEFAULT:\r
838\r
839 break;\r
840\r
841 case INPUT_STATE_ESC:\r
842\r
843 if (UnicodeChar == LEFTOPENBRACKET) {\r
844 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;\r
845 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
846 continue;\r
847 }\r
848\r
849 if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) {\r
850 TerminalDevice->InputState |= INPUT_STATE_O;\r
851 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
852 continue;\r
853 }\r
854\r
855 Key.ScanCode = SCAN_NULL;\r
856 \r
857 if (TerminalDevice->TerminalType == VT100PlusType || \r
858 TerminalDevice->TerminalType == VTUTF8Type) {\r
859 switch (UnicodeChar) {\r
860 case '1': \r
861 Key.ScanCode = SCAN_F1; \r
862 break;\r
863 case '2': \r
864 Key.ScanCode = SCAN_F2; \r
865 break;\r
866 case '3': \r
867 Key.ScanCode = SCAN_F3; \r
868 break;\r
869 case '4': \r
870 Key.ScanCode = SCAN_F4; \r
871 break;\r
872 case '5': \r
873 Key.ScanCode = SCAN_F5; \r
874 break;\r
875 case '6': \r
876 Key.ScanCode = SCAN_F6; \r
877 break;\r
878 case '7': \r
879 Key.ScanCode = SCAN_F7; \r
880 break;\r
881 case '8': \r
882 Key.ScanCode = SCAN_F8; \r
883 break;\r
884 case '9': \r
885 Key.ScanCode = SCAN_F9; \r
886 break;\r
887 case '0': \r
888 Key.ScanCode = SCAN_F10; \r
889 break;\r
890 case 'h': \r
891 Key.ScanCode = SCAN_HOME; \r
892 break;\r
893 case 'k': \r
894 Key.ScanCode = SCAN_END; \r
895 break;\r
896 case '+': \r
897 Key.ScanCode = SCAN_INSERT; \r
898 break;\r
899 case '-': \r
900 Key.ScanCode = SCAN_DELETE; \r
901 break;\r
902 case '/': \r
903 Key.ScanCode = SCAN_PAGE_DOWN; \r
904 break;\r
905 case '?': \r
906 Key.ScanCode = SCAN_PAGE_UP; \r
907 break; \r
908 default : \r
909 break;\r
910 }\r
911 }\r
912 \r
913 switch (UnicodeChar) {\r
914 case 'R': \r
915 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {\r
916 TerminalDevice->ResetState = RESET_STATE_ESC_R;\r
917 SetDefaultResetState = FALSE;\r
918 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {\r
919 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
920 }\r
921 Key.ScanCode = SCAN_NULL;\r
922 break;\r
923 case 'r': \r
924 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {\r
925 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;\r
926 SetDefaultResetState = FALSE;\r
927 }\r
928 Key.ScanCode = SCAN_NULL;\r
929 break;\r
930 default : \r
931 break;\r
932 }\r
933\r
934 if (SetDefaultResetState) {\r
935 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
936 }\r
937\r
938 if (Key.ScanCode != SCAN_NULL) {\r
939 Key.UnicodeChar = 0;\r
940 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
941 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
942 UnicodeToEfiKeyFlushState (TerminalDevice);\r
943 continue;\r
944 }\r
945\r
946 UnicodeToEfiKeyFlushState (TerminalDevice);\r
947\r
948 break;\r
949\r
950 case INPUT_STATE_ESC | INPUT_STATE_O:\r
951\r
952 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
953\r
954 Key.ScanCode = SCAN_NULL;\r
955 \r
956 if (TerminalDevice->TerminalType == VT100Type) {\r
957 switch (UnicodeChar) {\r
958 case 'P': \r
959 Key.ScanCode = SCAN_F1; \r
960 break;\r
961 case 'Q': \r
962 Key.ScanCode = SCAN_F2; \r
963 break;\r
964 case 'w': \r
965 Key.ScanCode = SCAN_F3; \r
966 break;\r
967 case 'x': \r
968 Key.ScanCode = SCAN_F4; \r
969 break;\r
970 case 't': \r
971 Key.ScanCode = SCAN_F5; \r
972 break;\r
973 case 'u': \r
974 Key.ScanCode = SCAN_F6; \r
975 break;\r
976 case 'q': \r
977 Key.ScanCode = SCAN_F7; \r
978 break;\r
979 case 'r': \r
980 Key.ScanCode = SCAN_F8; \r
981 break;\r
982 case 'p': \r
983 Key.ScanCode = SCAN_F9; \r
984 break;\r
985 case 'M': \r
986 Key.ScanCode = SCAN_F10; \r
987 break;\r
988 default : \r
989 break;\r
990 }\r
991 }\r
992\r
993 if (Key.ScanCode != SCAN_NULL) {\r
994 Key.UnicodeChar = 0;\r
995 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
996 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
997 UnicodeToEfiKeyFlushState (TerminalDevice);\r
998 continue;\r
999 }\r
1000\r
1001 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1002\r
1003 break;\r
1004\r
1005 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:\r
1006 \r
1007 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1008 \r
1009 Key.ScanCode = SCAN_NULL;\r
1010 \r
1011 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1012 TerminalDevice->TerminalType == VT100Type ||\r
1013 TerminalDevice->TerminalType == VT100PlusType || \r
1014 TerminalDevice->TerminalType == VTUTF8Type) {\r
1015 switch (UnicodeChar) {\r
1016 case 'A': \r
1017 Key.ScanCode = SCAN_UP; \r
1018 break;\r
1019 case 'B': \r
1020 Key.ScanCode = SCAN_DOWN; \r
1021 break;\r
1022 case 'C': \r
1023 Key.ScanCode = SCAN_RIGHT; \r
1024 break;\r
1025 case 'D': \r
1026 Key.ScanCode = SCAN_LEFT; \r
1027 break;\r
1028 case 'H': \r
1029 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1030 TerminalDevice->TerminalType == VT100Type) {\r
1031 Key.ScanCode = SCAN_HOME; \r
1032 }\r
1033 break;\r
1034 case 'F': \r
1035 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1036 Key.ScanCode = SCAN_END;\r
1037 }\r
1038 break;\r
1039 case 'K': \r
1040 if (TerminalDevice->TerminalType == VT100Type) {\r
1041 Key.ScanCode = SCAN_END; \r
1042 }\r
1043 break;\r
1044 case 'L': \r
1045 case '@': \r
1046 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1047 TerminalDevice->TerminalType == VT100Type) {\r
1048 Key.ScanCode = SCAN_INSERT; \r
1049 }\r
1050 break;\r
1051 case 'X': \r
1052 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1053 Key.ScanCode = SCAN_DELETE;\r
1054 }\r
1055 break;\r
1056 case 'P': \r
1057 if (TerminalDevice->TerminalType == VT100Type) {\r
1058 Key.ScanCode = SCAN_DELETE; \r
1059 } else if (TerminalDevice->TerminalType == PcAnsiType) {\r
1060 Key.ScanCode = SCAN_F4;\r
1061 }\r
1062 break;\r
1063 case 'I': \r
1064 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1065 Key.ScanCode = SCAN_PAGE_UP;\r
1066 }\r
1067 break; \r
1068 case 'V': \r
1069 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1070 Key.ScanCode = SCAN_F10;\r
1071 } \r
1072 case '?': \r
1073 if (TerminalDevice->TerminalType == VT100Type) {\r
1074 Key.ScanCode = SCAN_PAGE_UP; \r
1075 }\r
1076 break;\r
1077 case 'G': \r
1078 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1079 Key.ScanCode = SCAN_PAGE_DOWN;\r
1080 }\r
1081 break; \r
1082 case 'U': \r
1083 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1084 Key.ScanCode = SCAN_F9;\r
1085 }\r
1086 case '/': \r
1087 if (TerminalDevice->TerminalType == VT100Type) {\r
1088 Key.ScanCode = SCAN_PAGE_DOWN; \r
1089 }\r
1090 break;\r
1091 case 'M': \r
1092 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1093 Key.ScanCode = SCAN_F1;\r
1094 }\r
1095 break; \r
1096 case 'N': \r
1097 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1098 Key.ScanCode = SCAN_F2;\r
1099 }\r
1100 break; \r
1101 case 'O': \r
1102 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1103 Key.ScanCode = SCAN_F3;\r
1104 }\r
1105 break; \r
1106 case 'Q': \r
1107 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1108 Key.ScanCode = SCAN_F5;\r
1109 }\r
1110 break; \r
1111 case 'R': \r
1112 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1113 Key.ScanCode = SCAN_F6;\r
1114 }\r
1115 break; \r
1116 case 'S': \r
1117 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1118 Key.ScanCode = SCAN_F7;\r
1119 }\r
1120 break; \r
1121 case 'T': \r
1122 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1123 Key.ScanCode = SCAN_F8;\r
1124 }\r
1125 break; \r
1126 default : \r
1127 break;\r
1128 }\r
1129 }\r
1130\r
1131 if (Key.ScanCode != SCAN_NULL) {\r
1132 Key.UnicodeChar = 0;\r
1133 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1134 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
1135 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1136 continue;\r
1137 }\r
1138\r
1139 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1140\r
1141 break;\r
1142\r
1143 \r
1144 default:\r
1145 //\r
1146 // Invalid state. This should never happen.\r
1147 //\r
1148 ASSERT (FALSE);\r
1149\r
1150 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1151\r
1152 break;\r
1153 }\r
1154\r
1155 if (UnicodeChar == ESC) {\r
1156 TerminalDevice->InputState = INPUT_STATE_ESC;\r
1157 }\r
1158 \r
1159 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
1160 Status = gBS->SetTimer(\r
1161 TerminalDevice->TwoSecondTimeOut,\r
1162 TimerRelative,\r
1163 (UINT64)20000000\r
1164 );\r
1165 continue;\r
1166 }\r
1167\r
1168 if (SetDefaultResetState) {\r
1169 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1170 }\r
1171\r
1172 if (UnicodeChar == DEL) {\r
1173 Key.ScanCode = SCAN_DELETE;\r
1174 Key.UnicodeChar = 0;\r
1175 } else {\r
1176 Key.ScanCode = SCAN_NULL;\r
1177 Key.UnicodeChar = UnicodeChar;\r
1178 }\r
1179\r
1180 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1181 }\r
1182}\r