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