Beispiel #1
0
/**
  Update the Unicode characters from a terminal input device into EFI Keys FIFO.

  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys

**/
VOID
UnicodeToEfiKeyFlushState (
  IN  TERMINAL_DEV    *TerminalDevice
  )
{
  EFI_INPUT_KEY Key;
  UINT32        InputState;

  InputState = TerminalDevice->InputState;

  if (IsEfiKeyFiFoFull (TerminalDevice)) {
    return;
  }

  if ((InputState & INPUT_STATE_ESC) != 0) {
    Key.ScanCode    = SCAN_ESC;
    Key.UnicodeChar = 0;
    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }

  if ((InputState & INPUT_STATE_CSI) != 0) {
    Key.ScanCode    = SCAN_NULL;
    Key.UnicodeChar = CSI;
    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }

  if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
    Key.ScanCode    = SCAN_NULL;
    Key.UnicodeChar = LEFTOPENBRACKET;
    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }

  if ((InputState & INPUT_STATE_O) != 0) {
    Key.ScanCode    = SCAN_NULL;
    Key.UnicodeChar = 'O';
    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }

  if ((InputState & INPUT_STATE_2) != 0) {
    Key.ScanCode    = SCAN_NULL;
    Key.UnicodeChar = '2';
    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }

  //
  // Cancel the timer.
  //
  gBS->SetTimer (
        TerminalDevice->TwoSecondTimeOut,
        TimerCancel,
        0
        );

  TerminalDevice->InputState = INPUT_STATE_DEFAULT;
}
Beispiel #2
0
/**
  Insert one pre-fetched key into the FIFO buffer.

  @param  TerminalDevice       Terminal driver private structure.
  @param  Key                  The key will be input.

  @retval TRUE                 If insert successfully.
  @retval FLASE                If FIFO buffer is full before key insertion,
                               and the key is lost.

**/
BOOLEAN
EfiKeyFiFoInsertOneKey (
  TERMINAL_DEV                    *TerminalDevice,
  EFI_INPUT_KEY                   *Key
  )
{
  UINT8                           Tail;
  LIST_ENTRY                      *Link;
  LIST_ENTRY                      *NotifyList;
  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
  EFI_KEY_DATA                    KeyData;

  Tail = TerminalDevice->EfiKeyFiFo->Tail;

  CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
  KeyData.KeyState.KeyShiftState  = 0;
  KeyData.KeyState.KeyToggleState = 0;

  //
  // Invoke notification functions if exist
  //
  NotifyList = &TerminalDevice->NotifyList;
  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
    CurrentNotify = CR (
                      Link,
                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
                      NotifyEntry,
                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
                      );
    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
      CurrentNotify->KeyNotificationFn (&KeyData);
    }
  }
  if (IsEfiKeyFiFoFull (TerminalDevice)) {
    //
    // Efi Key FIFO is full
    //
    return FALSE;
  }

  CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));

  TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));

  return TRUE;
}
Beispiel #3
0
/**
  Insert one pre-fetched key into the FIFO buffer.

  @param  TerminalDevice       Terminal driver private structure.
  @param  Key                  The key will be input.

  @retval TRUE                 If insert successfully.
  @retval FLASE                If FIFO buffer is full before key insertion,
                               and the key is lost.

**/
BOOLEAN
EfiKeyFiFoInsertOneKey (
  TERMINAL_DEV      *TerminalDevice,
  EFI_INPUT_KEY     Key
  )
{
  UINT8 Tail;

  Tail = TerminalDevice->EfiKeyFiFo->Tail;
  ASSERT (Tail < FIFO_MAX_NUMBER + 1);

  if (IsEfiKeyFiFoFull (TerminalDevice)) {
    //
    // Efi Key FIFO is full
    //
    return FALSE;
  }

  TerminalDevice->EfiKeyFiFo->Data[Tail] = Key;

  TerminalDevice->EfiKeyFiFo->Tail       = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));

  return TRUE;
}
Beispiel #4
0
/**
  Converts a stream of Unicode characters from a terminal input device into EFI Keys that
  can be read through the Simple Input Protocol.

  The table below shows the keyboard input mappings that this function supports.
  If the ESC sequence listed in one of the columns is presented, then it is translated
  into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw
  key strokes are converted into EFI Keys.

  2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not
  completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
  converted into EFI Keys.
  There is one special input sequence that will force the system to reset.
  This is ESC R ESC r ESC R.

  Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100. 
        The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
        DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
        
  Symbols used in table below
  ===========================
    ESC = 0x1B
    CSI = 0x9B
    DEL = 0x7f
    ^   = CTRL

  +=========+======+===========+==========+==========+
  |         | EFI  | UEFI 2.0  |          |          |
  |         | Scan |           |  VT100+  |          |
  |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
  +=========+======+===========+==========+==========+
  | NULL    | 0x00 |           |          |          |
  | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
  | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
  | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
  | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
  | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
  | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
  | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
  |         |      | ESC [ L   |          | ESC [ L  |
  | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
  | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
  |         |      |           |          | ESC [ ?  |
  | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
  |         |      |           |          | ESC [ /  |
  | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
  | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
  | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
  | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
  | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
  | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
  | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
  | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
  | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
  | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
  | Escape  | 0x17 | ESC       | ESC      | ESC      |
  | F11     | 0x15 |           | ESC !    |          |
  | F12     | 0x16 |           | ESC @    |          |
  +=========+======+===========+==========+==========+

  Special Mappings
  ================
  ESC R ESC r ESC R = Reset System

  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys

**/
VOID
UnicodeToEfiKey (
  IN  TERMINAL_DEV    *TerminalDevice
  )
{
  EFI_STATUS          Status;
  EFI_STATUS          TimerStatus;
  UINT16              UnicodeChar;
  EFI_INPUT_KEY       Key;
  BOOLEAN             SetDefaultResetState;

  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);

  if (!EFI_ERROR (TimerStatus)) {
    UnicodeToEfiKeyFlushState (TerminalDevice);
    TerminalDevice->ResetState = RESET_STATE_DEFAULT;
  }

  while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {

    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
      //
      // Check to see if the 2 seconds timer has expired
      //
      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
      if (!EFI_ERROR (TimerStatus)) {
        UnicodeToEfiKeyFlushState (TerminalDevice);
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
      }
    }

    //
    // Fetch one Unicode character from the Unicode FIFO
    //
    UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);

    SetDefaultResetState = TRUE;

    switch (TerminalDevice->InputState) {
    case INPUT_STATE_DEFAULT:

      break;

    case INPUT_STATE_ESC:

      if (UnicodeChar == LEFTOPENBRACKET) {
        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
        continue;
      }

      if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
        TerminalDevice->InputState |= INPUT_STATE_O;
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
        continue;
      }

      Key.ScanCode = SCAN_NULL;

      if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
          TerminalDevice->TerminalType == VTUTF8TYPE) {
        switch (UnicodeChar) {
        case '1':
          Key.ScanCode = SCAN_F1;
          break;
        case '2':
          Key.ScanCode = SCAN_F2;
          break;
        case '3':
          Key.ScanCode = SCAN_F3;
          break;
        case '4':
          Key.ScanCode = SCAN_F4;
          break;
        case '5':
          Key.ScanCode = SCAN_F5;
          break;
        case '6':
          Key.ScanCode = SCAN_F6;
          break;
        case '7':
          Key.ScanCode = SCAN_F7;
          break;
        case '8':
          Key.ScanCode = SCAN_F8;
          break;
        case '9':
          Key.ScanCode = SCAN_F9;
          break;
        case '0':
          Key.ScanCode = SCAN_F10;
          break;
        case '!':
          Key.ScanCode = SCAN_F11;
          break;
        case '@':
          Key.ScanCode = SCAN_F12;
          break;
        case 'h':
          Key.ScanCode = SCAN_HOME;
          break;
        case 'k':
          Key.ScanCode = SCAN_END;
          break;
        case '+':
          Key.ScanCode = SCAN_INSERT;
          break;
        case '-':
          Key.ScanCode = SCAN_DELETE;
          break;
        case '/':
          Key.ScanCode = SCAN_PAGE_DOWN;
          break;
        case '?':
          Key.ScanCode = SCAN_PAGE_UP;
          break;
        default :
          break;
        }
      }

      switch (UnicodeChar) {
      case 'R':
        if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
          TerminalDevice->ResetState = RESET_STATE_ESC_R;
          SetDefaultResetState = FALSE;
        } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
          gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
        }
        Key.ScanCode = SCAN_NULL;
        break;
      case 'r':
        if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
          TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
          SetDefaultResetState = FALSE;
        }
        Key.ScanCode = SCAN_NULL;
        break;
      default :
        break;
      }

      if (SetDefaultResetState) {
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_O:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      Key.ScanCode = SCAN_NULL;

      if (TerminalDevice->TerminalType == VT100TYPE) {
        switch (UnicodeChar) {
        case 'P':
          Key.ScanCode = SCAN_F1;
          break;
        case 'Q':
          Key.ScanCode = SCAN_F2;
          break;
        case 'w':
          Key.ScanCode = SCAN_F3;
          break;
        case 'x':
          Key.ScanCode = SCAN_F4;
          break;
        case 't':
          Key.ScanCode = SCAN_F5;
          break;
        case 'u':
          Key.ScanCode = SCAN_F6;
          break;
        case 'q':
          Key.ScanCode = SCAN_F7;
          break;
        case 'r':
          Key.ScanCode = SCAN_F8;
          break;
        case 'p':
          Key.ScanCode = SCAN_F9;
          break;
        case 'M':
          Key.ScanCode = SCAN_F10;
          break;
        default :
          break;
        }
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      Key.ScanCode = SCAN_NULL;

      if (TerminalDevice->TerminalType == PCANSITYPE    ||
          TerminalDevice->TerminalType == VT100TYPE     ||
          TerminalDevice->TerminalType == VT100PLUSTYPE ||
          TerminalDevice->TerminalType == VTUTF8TYPE) {
        switch (UnicodeChar) {
        case 'A':
          Key.ScanCode = SCAN_UP;
          break;
        case 'B':
          Key.ScanCode = SCAN_DOWN;
          break;
        case 'C':
          Key.ScanCode = SCAN_RIGHT;
          break;
        case 'D':
          Key.ScanCode = SCAN_LEFT;
          break;
        case 'H':
          if (TerminalDevice->TerminalType == PCANSITYPE ||
              TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_HOME;
          }
          break;
        case 'F':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_END;
          }
          break;
        case 'K':
          if (TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_END;
          }
          break;
        case 'L':
        case '@':
          if (TerminalDevice->TerminalType == PCANSITYPE ||
              TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_INSERT;
          }
          break;
        case 'X':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_DELETE;
          }
          break;
        case 'P':
          if (TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_DELETE;
          } else if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F4;
          }
          break;
        case 'I':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_PAGE_UP;
          }
          break;
        case 'V':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F10;
          }
          break;
        case '?':
          if (TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_PAGE_UP;
          }
          break;
        case 'G':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_PAGE_DOWN;
          }
          break;
        case 'U':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F9;
          }
          break;
        case '/':
          if (TerminalDevice->TerminalType == VT100TYPE) {
            Key.ScanCode = SCAN_PAGE_DOWN;
          }
          break;
        case 'M':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F1;
          }
          break;
        case 'N':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F2;
          }
          break;
        case 'O':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F3;
          }
          break;
        case 'Q':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F5;
          }
          break;
        case 'R':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F6;
          }
          break;
        case 'S':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F7;
          }
          break;
        case 'T':
          if (TerminalDevice->TerminalType == PCANSITYPE) {
            Key.ScanCode = SCAN_F8;
          }
          break;
        default :
          break;
        }
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;


    default:
      //
      // Invalid state. This should never happen.
      //
      ASSERT (FALSE);

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;
    }

    if (UnicodeChar == ESC) {
      TerminalDevice->InputState = INPUT_STATE_ESC;
    }

    if (UnicodeChar == CSI) {
      TerminalDevice->InputState = INPUT_STATE_CSI;
    }

    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
      Status = gBS->SetTimer(
                      TerminalDevice->TwoSecondTimeOut,
                      TimerRelative,
                      (UINT64)20000000
                      );
      ASSERT_EFI_ERROR (Status);
      continue;
    }

    if (SetDefaultResetState) {
      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
    }

    if (UnicodeChar == DEL) {
      Key.ScanCode    = SCAN_DELETE;
      Key.UnicodeChar = 0;
    } else {
      Key.ScanCode    = SCAN_NULL;
      Key.UnicodeChar = UnicodeChar;
    }

    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
  }
}