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