]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[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
1cc8ee78 271 (EFI_PARITY_TYPE) (Mode->Parity),\r
878ddf1f 272 (UINT8) Mode->DataBits,\r
1cc8ee78 273 (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
878ddf1f 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
1cc8ee78 684STATIC\r
878ddf1f 685VOID\r
686UnicodeToEfiKeyFlushState (\r
687 IN TERMINAL_DEV *TerminalDevice\r
688 )\r
689{\r
690 EFI_INPUT_KEY Key;\r
691\r
692 if (TerminalDevice->InputState & INPUT_STATE_ESC) {\r
693 Key.ScanCode = SCAN_ESC;\r
694 Key.UnicodeChar = 0;\r
695 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
696 }\r
697\r
698 if (TerminalDevice->InputState & INPUT_STATE_CSI) {\r
699 Key.ScanCode = SCAN_NULL;\r
700 Key.UnicodeChar = CSI;\r
701 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
702 }\r
703\r
704 if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) {\r
705 Key.ScanCode = SCAN_NULL;\r
706 Key.UnicodeChar = LEFTOPENBRACKET;\r
707 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
708 }\r
709\r
710 if (TerminalDevice->InputState & INPUT_STATE_O) {\r
711 Key.ScanCode = SCAN_NULL;\r
712 Key.UnicodeChar = 'O';\r
713 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
714 }\r
715\r
716 if (TerminalDevice->InputState & INPUT_STATE_2) {\r
717 Key.ScanCode = SCAN_NULL;\r
718 Key.UnicodeChar = '2';\r
719 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
720 }\r
721\r
722 gBS->SetTimer (\r
723 TerminalDevice->TwoSecondTimeOut,\r
724 TimerCancel,\r
725 0\r
726 );\r
727\r
728 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
729}\r
730\r
731VOID\r
732UnicodeToEfiKey (\r
733 IN TERMINAL_DEV *TerminalDevice\r
734 )\r
735/*++\r
736 Routine Description:\r
737 \r
738 Converts a stream of Unicode characters from a terminal input device into EFI Keys that\r
739 can be read through the Simple Input Protocol. The table below shows the keyboard\r
740 input mappings that this function supports. If the ESC sequence listed in one of the \r
741 columns is presented, then it is translated into the coorespoding EFI Scan Code. If a\r
742 matching sequence is not found, then the raw key strokes are converted into EFI Keys.\r
743 \r
744 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not \r
745 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are \r
746 converted into EFI Keys.\r
747 \r
748 There is one special input sequence that will force the system to reset. \r
749 This is ESC R ESC r ESC R.\r
750 \r
751 Arguments:\r
752\r
753 TerminaDevice : The terminal device to use to translate raw input into EFI Keys\r
754 \r
755 Returns:\r
756\r
757 None\r
758\r
759Symbols used in table below\r
760===========================\r
761 ESC = 0x1B \r
762 CSI = 0x9B \r
763 DEL = 0x7f \r
764 ^ = CTRL\r
765\r
766+=========+======+===========+==========+==========+\r
767| | EFI | EFI 1.10 | | |\r
768| | Scan | | VT100+ | |\r
769| KEY | Code | PC ANSI | VTUTF8 | VT100 |\r
770+=========+======+===========+==========+==========+\r
771| NULL | 0x00 | | | |\r
772| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |\r
773| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |\r
774| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | \r
775| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |\r
776| HOME | 0x05 | ESC [ H | ESC h | ESC [ H |\r
777| END | 0x06 | ESC [ F | ESC k | ESC [ K |\r
778| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |\r
779| | | ESC [ L | | ESC [ L |\r
780| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |\r
781| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |\r
782| | | | | ESC [ ? |\r
783| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |\r
784| | | | | ESC [ / |\r
785| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |\r
786| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |\r
787| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |\r
788| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |\r
789| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |\r
790| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |\r
791| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |\r
792| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |\r
793| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |\r
794| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |\r
795| Escape | 0x17 | ESC | ESC | ESC |\r
796+=========+======+===========+==========+=========+\r
797\r
798Special Mappings\r
799================\r
800ESC R ESC r ESC R = Reset System\r
801\r
802--*/\r
803{\r
804 EFI_STATUS Status;\r
805 EFI_STATUS TimerStatus;\r
806 UINT16 UnicodeChar;\r
807 EFI_INPUT_KEY Key;\r
808 BOOLEAN SetDefaultResetState;\r
809 \r
810 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
811\r
812 if (!EFI_ERROR (TimerStatus)) {\r
813 UnicodeToEfiKeyFlushState (TerminalDevice);\r
814 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
815 }\r
816\r
817 while (!IsUnicodeFiFoEmpty(TerminalDevice)) {\r
818 \r
819 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
820 //\r
821 // Check to see if the 2 second timer has expired\r
822 //\r
823 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
824 if (!EFI_ERROR (TimerStatus)) {\r
825 UnicodeToEfiKeyFlushState (TerminalDevice);\r
826 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
827 }\r
828 }\r
829\r
830 //\r
831 // Fetch one Unicode character from the Unicode FIFO\r
832 //\r
833 UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar);\r
834\r
835 SetDefaultResetState = TRUE;\r
836\r
837 switch (TerminalDevice->InputState) {\r
838 case INPUT_STATE_DEFAULT:\r
839\r
840 break;\r
841\r
842 case INPUT_STATE_ESC:\r
843\r
844 if (UnicodeChar == LEFTOPENBRACKET) {\r
845 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;\r
846 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
847 continue;\r
848 }\r
849\r
850 if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) {\r
851 TerminalDevice->InputState |= INPUT_STATE_O;\r
852 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
853 continue;\r
854 }\r
855\r
856 Key.ScanCode = SCAN_NULL;\r
857 \r
858 if (TerminalDevice->TerminalType == VT100PlusType || \r
859 TerminalDevice->TerminalType == VTUTF8Type) {\r
860 switch (UnicodeChar) {\r
861 case '1': \r
862 Key.ScanCode = SCAN_F1; \r
863 break;\r
864 case '2': \r
865 Key.ScanCode = SCAN_F2; \r
866 break;\r
867 case '3': \r
868 Key.ScanCode = SCAN_F3; \r
869 break;\r
870 case '4': \r
871 Key.ScanCode = SCAN_F4; \r
872 break;\r
873 case '5': \r
874 Key.ScanCode = SCAN_F5; \r
875 break;\r
876 case '6': \r
877 Key.ScanCode = SCAN_F6; \r
878 break;\r
879 case '7': \r
880 Key.ScanCode = SCAN_F7; \r
881 break;\r
882 case '8': \r
883 Key.ScanCode = SCAN_F8; \r
884 break;\r
885 case '9': \r
886 Key.ScanCode = SCAN_F9; \r
887 break;\r
888 case '0': \r
889 Key.ScanCode = SCAN_F10; \r
890 break;\r
891 case 'h': \r
892 Key.ScanCode = SCAN_HOME; \r
893 break;\r
894 case 'k': \r
895 Key.ScanCode = SCAN_END; \r
896 break;\r
897 case '+': \r
898 Key.ScanCode = SCAN_INSERT; \r
899 break;\r
900 case '-': \r
901 Key.ScanCode = SCAN_DELETE; \r
902 break;\r
903 case '/': \r
904 Key.ScanCode = SCAN_PAGE_DOWN; \r
905 break;\r
906 case '?': \r
907 Key.ScanCode = SCAN_PAGE_UP; \r
908 break; \r
909 default : \r
910 break;\r
911 }\r
912 }\r
913 \r
914 switch (UnicodeChar) {\r
915 case 'R': \r
916 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {\r
917 TerminalDevice->ResetState = RESET_STATE_ESC_R;\r
918 SetDefaultResetState = FALSE;\r
919 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {\r
920 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
921 }\r
922 Key.ScanCode = SCAN_NULL;\r
923 break;\r
924 case 'r': \r
925 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {\r
926 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;\r
927 SetDefaultResetState = FALSE;\r
928 }\r
929 Key.ScanCode = SCAN_NULL;\r
930 break;\r
931 default : \r
932 break;\r
933 }\r
934\r
935 if (SetDefaultResetState) {\r
936 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
937 }\r
938\r
939 if (Key.ScanCode != SCAN_NULL) {\r
940 Key.UnicodeChar = 0;\r
941 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
942 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
943 UnicodeToEfiKeyFlushState (TerminalDevice);\r
944 continue;\r
945 }\r
946\r
947 UnicodeToEfiKeyFlushState (TerminalDevice);\r
948\r
949 break;\r
950\r
951 case INPUT_STATE_ESC | INPUT_STATE_O:\r
952\r
953 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
954\r
955 Key.ScanCode = SCAN_NULL;\r
956 \r
957 if (TerminalDevice->TerminalType == VT100Type) {\r
958 switch (UnicodeChar) {\r
959 case 'P': \r
960 Key.ScanCode = SCAN_F1; \r
961 break;\r
962 case 'Q': \r
963 Key.ScanCode = SCAN_F2; \r
964 break;\r
965 case 'w': \r
966 Key.ScanCode = SCAN_F3; \r
967 break;\r
968 case 'x': \r
969 Key.ScanCode = SCAN_F4; \r
970 break;\r
971 case 't': \r
972 Key.ScanCode = SCAN_F5; \r
973 break;\r
974 case 'u': \r
975 Key.ScanCode = SCAN_F6; \r
976 break;\r
977 case 'q': \r
978 Key.ScanCode = SCAN_F7; \r
979 break;\r
980 case 'r': \r
981 Key.ScanCode = SCAN_F8; \r
982 break;\r
983 case 'p': \r
984 Key.ScanCode = SCAN_F9; \r
985 break;\r
986 case 'M': \r
987 Key.ScanCode = SCAN_F10; \r
988 break;\r
989 default : \r
990 break;\r
991 }\r
992 }\r
993\r
994 if (Key.ScanCode != SCAN_NULL) {\r
995 Key.UnicodeChar = 0;\r
996 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
997 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
998 UnicodeToEfiKeyFlushState (TerminalDevice);\r
999 continue;\r
1000 }\r
1001\r
1002 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1003\r
1004 break;\r
1005\r
1006 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:\r
1007 \r
1008 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1009 \r
1010 Key.ScanCode = SCAN_NULL;\r
1011 \r
1012 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1013 TerminalDevice->TerminalType == VT100Type ||\r
1014 TerminalDevice->TerminalType == VT100PlusType || \r
1015 TerminalDevice->TerminalType == VTUTF8Type) {\r
1016 switch (UnicodeChar) {\r
1017 case 'A': \r
1018 Key.ScanCode = SCAN_UP; \r
1019 break;\r
1020 case 'B': \r
1021 Key.ScanCode = SCAN_DOWN; \r
1022 break;\r
1023 case 'C': \r
1024 Key.ScanCode = SCAN_RIGHT; \r
1025 break;\r
1026 case 'D': \r
1027 Key.ScanCode = SCAN_LEFT; \r
1028 break;\r
1029 case 'H': \r
1030 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1031 TerminalDevice->TerminalType == VT100Type) {\r
1032 Key.ScanCode = SCAN_HOME; \r
1033 }\r
1034 break;\r
1035 case 'F': \r
1036 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1037 Key.ScanCode = SCAN_END;\r
1038 }\r
1039 break;\r
1040 case 'K': \r
1041 if (TerminalDevice->TerminalType == VT100Type) {\r
1042 Key.ScanCode = SCAN_END; \r
1043 }\r
1044 break;\r
1045 case 'L': \r
1046 case '@': \r
1047 if (TerminalDevice->TerminalType == PcAnsiType ||\r
1048 TerminalDevice->TerminalType == VT100Type) {\r
1049 Key.ScanCode = SCAN_INSERT; \r
1050 }\r
1051 break;\r
1052 case 'X': \r
1053 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1054 Key.ScanCode = SCAN_DELETE;\r
1055 }\r
1056 break;\r
1057 case 'P': \r
1058 if (TerminalDevice->TerminalType == VT100Type) {\r
1059 Key.ScanCode = SCAN_DELETE; \r
1060 } else if (TerminalDevice->TerminalType == PcAnsiType) {\r
1061 Key.ScanCode = SCAN_F4;\r
1062 }\r
1063 break;\r
1064 case 'I': \r
1065 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1066 Key.ScanCode = SCAN_PAGE_UP;\r
1067 }\r
1068 break; \r
1069 case 'V': \r
1070 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1071 Key.ScanCode = SCAN_F10;\r
1072 } \r
1073 case '?': \r
1074 if (TerminalDevice->TerminalType == VT100Type) {\r
1075 Key.ScanCode = SCAN_PAGE_UP; \r
1076 }\r
1077 break;\r
1078 case 'G': \r
1079 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1080 Key.ScanCode = SCAN_PAGE_DOWN;\r
1081 }\r
1082 break; \r
1083 case 'U': \r
1084 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1085 Key.ScanCode = SCAN_F9;\r
1086 }\r
1087 case '/': \r
1088 if (TerminalDevice->TerminalType == VT100Type) {\r
1089 Key.ScanCode = SCAN_PAGE_DOWN; \r
1090 }\r
1091 break;\r
1092 case 'M': \r
1093 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1094 Key.ScanCode = SCAN_F1;\r
1095 }\r
1096 break; \r
1097 case 'N': \r
1098 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1099 Key.ScanCode = SCAN_F2;\r
1100 }\r
1101 break; \r
1102 case 'O': \r
1103 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1104 Key.ScanCode = SCAN_F3;\r
1105 }\r
1106 break; \r
1107 case 'Q': \r
1108 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1109 Key.ScanCode = SCAN_F5;\r
1110 }\r
1111 break; \r
1112 case 'R': \r
1113 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1114 Key.ScanCode = SCAN_F6;\r
1115 }\r
1116 break; \r
1117 case 'S': \r
1118 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1119 Key.ScanCode = SCAN_F7;\r
1120 }\r
1121 break; \r
1122 case 'T': \r
1123 if (TerminalDevice->TerminalType == PcAnsiType) {\r
1124 Key.ScanCode = SCAN_F8;\r
1125 }\r
1126 break; \r
1127 default : \r
1128 break;\r
1129 }\r
1130 }\r
1131\r
1132 if (Key.ScanCode != SCAN_NULL) {\r
1133 Key.UnicodeChar = 0;\r
1134 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1135 TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
1136 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1137 continue;\r
1138 }\r
1139\r
1140 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1141\r
1142 break;\r
1143\r
1144 \r
1145 default:\r
1146 //\r
1147 // Invalid state. This should never happen.\r
1148 //\r
1149 ASSERT (FALSE);\r
1150\r
1151 UnicodeToEfiKeyFlushState (TerminalDevice);\r
1152\r
1153 break;\r
1154 }\r
1155\r
1156 if (UnicodeChar == ESC) {\r
1157 TerminalDevice->InputState = INPUT_STATE_ESC;\r
1158 }\r
1159 \r
1160 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
1161 Status = gBS->SetTimer(\r
1162 TerminalDevice->TwoSecondTimeOut,\r
1163 TimerRelative,\r
1164 (UINT64)20000000\r
1165 );\r
1cc8ee78 1166 ASSERT_EFI_ERROR (Status);\r
878ddf1f 1167 continue;\r
1168 }\r
1169\r
1170 if (SetDefaultResetState) {\r
1171 TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1172 }\r
1173\r
1174 if (UnicodeChar == DEL) {\r
1175 Key.ScanCode = SCAN_DELETE;\r
1176 Key.UnicodeChar = 0;\r
1177 } else {\r
1178 Key.ScanCode = SCAN_NULL;\r
1179 Key.UnicodeChar = UnicodeChar;\r
1180 }\r
1181\r
1182 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1183 }\r
1184}\r