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