audk/MdeModulePkg/Bus/Usb/UsbKbDxe/keyboard.c

1316 lines
34 KiB
C
Raw Normal View History

/** @file
Copyright (c) 2004 - 2005, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Keyboard.c
Abstract:
Helper functions for USB Keyboard Driver
Revision History
**/
#include "keyboard.h"
#include <Library/UsbLib.h>
//
// USB Key Code to Efi key mapping table
// Format:<efi scan code>, <unicode without shift>, <unicode with shift>
//
STATIC
UINT8 KeyConvertionTable[USB_KEYCODE_MAX_MAKE][3] = {
{ SCAN_NULL, 'a', 'A' }, // 0x04
{ SCAN_NULL, 'b', 'B' }, // 0x05
{ SCAN_NULL, 'c', 'C' }, // 0x06
{ SCAN_NULL, 'd', 'D' }, // 0x07
{ SCAN_NULL, 'e', 'E' }, // 0x08
{ SCAN_NULL, 'f', 'F' }, // 0x09
{ SCAN_NULL, 'g', 'G' }, // 0x0A
{ SCAN_NULL, 'h', 'H' }, // 0x0B
{ SCAN_NULL, 'i', 'I' }, // 0x0C
{ SCAN_NULL, 'j', 'J' }, // 0x0D
{ SCAN_NULL, 'k', 'K' }, // 0x0E
{ SCAN_NULL, 'l', 'L' }, // 0x0F
{ SCAN_NULL, 'm', 'M' }, // 0x10
{ SCAN_NULL, 'n', 'N' }, // 0x11
{ SCAN_NULL, 'o', 'O' }, // 0x12
{ SCAN_NULL, 'p', 'P' }, // 0x13
{ SCAN_NULL, 'q', 'Q' }, // 0x14
{ SCAN_NULL, 'r', 'R' }, // 0x15
{ SCAN_NULL, 's', 'S' }, // 0x16
{ SCAN_NULL, 't', 'T' }, // 0x17
{ SCAN_NULL, 'u', 'U' }, // 0x18
{ SCAN_NULL, 'v', 'V' }, // 0x19
{ SCAN_NULL, 'w', 'W' }, // 0x1A
{ SCAN_NULL, 'x', 'X' }, // 0x1B
{ SCAN_NULL, 'y', 'Y' }, // 0x1C
{ SCAN_NULL, 'z', 'Z' }, // 0x1D
{ SCAN_NULL, '1', '!' }, // 0x1E
{ SCAN_NULL, '2', '@' }, // 0x1F
{ SCAN_NULL, '3', '#' }, // 0x20
{ SCAN_NULL, '4', '$' }, // 0x21
{ SCAN_NULL, '5', '%' }, // 0x22
{ SCAN_NULL, '6', '^' }, // 0x23
{ SCAN_NULL, '7', '&' }, // 0x24
{ SCAN_NULL, '8', '*' }, // 0x25
{ SCAN_NULL, '9', '(' }, // 0x26
{ SCAN_NULL, '0', ')' }, // 0x27
{ SCAN_NULL, 0x0d, 0x0d }, // 0x28 Enter
{ SCAN_ESC, 0x00, 0x00 }, // 0x29 Esc
{ SCAN_NULL, 0x08, 0x08 }, // 0x2A Backspace
{ SCAN_NULL, 0x09, 0x09 }, // 0x2B Tab
{ SCAN_NULL, ' ', ' ' }, // 0x2C Spacebar
{ SCAN_NULL, '-', '_' }, // 0x2D
{ SCAN_NULL, '=', '+' }, // 0x2E
{ SCAN_NULL, '[', '{' }, // 0x2F
{ SCAN_NULL, ']', '}' }, // 0x30
{ SCAN_NULL, '\\', '|' }, // 0x31
{ SCAN_NULL, '\\', '|' }, // 0x32 Keyboard US \ and |
{ SCAN_NULL, ';', ':' }, // 0x33
{ SCAN_NULL, '\'', '"' }, // 0x34
{ SCAN_NULL, '`', '~' }, // 0x35 Keyboard Grave Accent and Tlide
{ SCAN_NULL, ',', '<' }, // 0x36
{ SCAN_NULL, '.', '>' }, // 0x37
{ SCAN_NULL, '/', '?' }, // 0x38
{ SCAN_NULL, 0x00, 0x00 }, // 0x39 CapsLock
{ SCAN_F1, 0x00, 0x00 }, // 0x3A
{ SCAN_F2, 0x00, 0x00 }, // 0x3B
{ SCAN_F3, 0x00, 0x00 }, // 0x3C
{ SCAN_F4, 0x00, 0x00 }, // 0x3D
{ SCAN_F5, 0x00, 0x00 }, // 0x3E
{ SCAN_F6, 0x00, 0x00 }, // 0x3F
{ SCAN_F7, 0x00, 0x00 }, // 0x40
{ SCAN_F8, 0x00, 0x00 }, // 0x41
{ SCAN_F9, 0x00, 0x00 }, // 0x42
{ SCAN_F10, 0x00, 0x00 }, // 0x43
{ SCAN_F11, 0x00, 0x00 }, // 0x44 F11
{ SCAN_F12, 0x00, 0x00 }, // 0x45 F12
{ SCAN_NULL, 0x00, 0x00 }, // 0x46 PrintScreen
{ SCAN_NULL, 0x00, 0x00 }, // 0x47 Scroll Lock
{ SCAN_NULL, 0x00, 0x00 }, // 0x48 Pause
{ SCAN_INSERT, 0x00, 0x00 }, // 0x49
{ SCAN_HOME, 0x00, 0x00 }, // 0x4A
{ SCAN_PAGE_UP, 0x00, 0x00 }, // 0x4B
{ SCAN_DELETE, 0x00, 0x00 }, // 0x4C
{ SCAN_END, 0x00, 0x00 }, // 0x4D
{ SCAN_PAGE_DOWN, 0x00, 0x00 }, // 0x4E
{ SCAN_RIGHT, 0x00, 0x00 }, // 0x4F
{ SCAN_LEFT, 0x00, 0x00 }, // 0x50
{ SCAN_DOWN, 0x00, 0x00 }, // 0x51
{ SCAN_UP, 0x00, 0x00 }, // 0x52
{ SCAN_NULL, 0x00, 0x00 }, // 0x53 NumLock
{ SCAN_NULL, '/', '/' }, // 0x54
{ SCAN_NULL, '*', '*' }, // 0x55
{ SCAN_NULL, '-', '-' }, // 0x56
{ SCAN_NULL, '+', '+' }, // 0x57
{ SCAN_NULL, 0x0d, 0x0d }, // 0x58
{ SCAN_END, '1', '1' }, // 0x59
{ SCAN_DOWN, '2', '2' }, // 0x5A
{ SCAN_PAGE_DOWN, '3', '3' }, // 0x5B
{ SCAN_LEFT, '4', '4' }, // 0x5C
{ SCAN_NULL, '5', '5' }, // 0x5D
{ SCAN_RIGHT, '6', '6' }, // 0x5E
{ SCAN_HOME, '7', '7' }, // 0x5F
{ SCAN_UP, '8', '8' }, // 0x60
{ SCAN_PAGE_UP, '9', '9' }, // 0x61
{ SCAN_INSERT, '0', '0' }, // 0x62
{ SCAN_DELETE, '.', '.' }, // 0x63
{ SCAN_NULL, '\\', '|' }, // 0x64 Keyboard Non-US \ and |
{ SCAN_NULL, 0x00, 0x00 }, // 0x65 Keyboard Application
{ SCAN_NULL, 0x00, 0x00 }, // 0x66 Keyboard Power
{ SCAN_NULL, '=' , '=' }, // 0x67 Keypad =
{ SCAN_F13, 0x00, 0x00 }, // 0x68
{ SCAN_F14, 0x00, 0x00 }, // 0x69
{ SCAN_F15, 0x00, 0x00 }, // 0x6A
{ SCAN_F16, 0x00, 0x00 }, // 0x6B
{ SCAN_F17, 0x00, 0x00 }, // 0x6C
{ SCAN_F18, 0x00, 0x00 }, // 0x6D
{ SCAN_F19, 0x00, 0x00 }, // 0x6E
{ SCAN_F20, 0x00, 0x00 }, // 0x6F
{ SCAN_F21, 0x00, 0x00 }, // 0x70
{ SCAN_F22, 0x00, 0x00 }, // 0x71
{ SCAN_F23, 0x00, 0x00 }, // 0x72
{ SCAN_F24, 0x00, 0x00 }, // 0x73
{ SCAN_MUTE, 0x00, 0x00 }, // 0x7F
{ SCAN_VOLUME_UP, 0x00, 0x00 }, // 0x80
{ SCAN_VOLUME_DOWN, 0x00, 0x00 }, // 0x81
};
STATIC KB_MODIFIER KB_Mod[8] = {
{ MOD_CONTROL_L, 0xe0 }, // 11100000
{ MOD_CONTROL_R, 0xe4 }, // 11100100
{ MOD_SHIFT_L, 0xe1 }, // 11100001
{ MOD_SHIFT_R, 0xe5 }, // 11100101
{ MOD_ALT_L, 0xe2 }, // 11100010
{ MOD_ALT_R, 0xe6 }, // 11100110
{ MOD_WIN_L, 0xe3 }, // 11100011
{ MOD_WIN_R, 0xe7 }, // 11100111
};
/**
Uses USB I/O to check whether the device is a USB Keyboard device.
UsbIo: Points to a USB I/O protocol instance.
**/
BOOLEAN
IsUSBKeyboard (
IN EFI_USB_IO_PROTOCOL *UsbIo
)
{
EFI_STATUS Status;
EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
//
// Get the Default interface descriptor, currently we
// assume it is interface 1
//
Status = UsbIo->UsbGetInterfaceDescriptor (
UsbIo,
&InterfaceDescriptor
);
if (EFI_ERROR (Status)) {
return FALSE;
}
if (InterfaceDescriptor.InterfaceClass == CLASS_HID &&
InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT &&
InterfaceDescriptor.InterfaceProtocol == PROTOCOL_KEYBOARD
) {
return TRUE;
}
return FALSE;
}
/**
Initialize USB Keyboard device and all private data structures.
UsbKeyboardDevice The USB_KB_DEV instance.
@retval EFI_SUCCESS Success
@retval EFI_DEVICE_ERROR Hardware Error
**/
EFI_STATUS
InitUSBKeyboard (
IN USB_KB_DEV *UsbKeyboardDevice
)
{
UINT8 ConfigValue;
UINT8 Protocol;
UINT8 ReportId;
UINT8 Duration;
EFI_STATUS Status;
UINT32 TransferResult;
KbdReportStatusCode (
UsbKeyboardDevice->DevicePath,
EFI_PROGRESS_CODE,
PcdGet32 (PcdStatusCodeValueKeyboardSelfTest)
);
InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));
//
// default configurations
//
ConfigValue = 0x01;
//
// Uses default configuration to configure the USB Keyboard device.
//
Status = UsbSetConfiguration (
UsbKeyboardDevice->UsbIo,
(UINT16) ConfigValue,
&TransferResult
);
if (EFI_ERROR (Status)) {
//
// If configuration could not be set here, it means
// the keyboard interface has some errors and could
// not be initialized
//
KbdReportStatusCode (
UsbKeyboardDevice->DevicePath,
EFI_ERROR_CODE | EFI_ERROR_MINOR,
PcdGet32 (PcdStatusCodeValueKeyboardInterfaceError)
);
return EFI_DEVICE_ERROR;
}
UsbGetProtocolRequest (
UsbKeyboardDevice->UsbIo,
UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
&Protocol
);
//
// Sets boot protocol for the USB Keyboard.
// This driver only supports boot protocol.
// !!BugBug: How about the device that does not support boot protocol?
//
if (Protocol != BOOT_PROTOCOL) {
UsbSetProtocolRequest (
UsbKeyboardDevice->UsbIo,
UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
BOOT_PROTOCOL
);
}
//
// the duration is indefinite, so the endpoint will inhibit reporting forever,
// and only reporting when a change is detected in the report data.
//
//
// idle value for all report ID
//
ReportId = 0;
//
// idle forever until there is a key pressed and released.
//
Duration = 0;
UsbSetIdleRequest (
UsbKeyboardDevice->UsbIo,
UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
ReportId,
Duration
);
UsbKeyboardDevice->CtrlOn = 0;
UsbKeyboardDevice->AltOn = 0;
UsbKeyboardDevice->ShiftOn = 0;
UsbKeyboardDevice->NumLockOn = 0;
UsbKeyboardDevice->CapsOn = 0;
UsbKeyboardDevice->ScrollOn = 0;
UsbKeyboardDevice->LeftCtrlOn = 0;
UsbKeyboardDevice->LeftAltOn = 0;
UsbKeyboardDevice->LeftShiftOn = 0;
UsbKeyboardDevice->LeftLogoOn = 0;
UsbKeyboardDevice->RightCtrlOn = 0;
UsbKeyboardDevice->RightAltOn = 0;
UsbKeyboardDevice->RightShiftOn = 0;
UsbKeyboardDevice->RightLogoOn = 0;
UsbKeyboardDevice->MenuKeyOn = 0;
UsbKeyboardDevice->SysReqOn = 0;
//
// Sync the initial state of lights
//
SetKeyLED (UsbKeyboardDevice);
ZeroMem (UsbKeyboardDevice->LastKeyCodeArray, sizeof (UINT8) * 8);
//
// Set a timer for repeat keys' generation.
//
if (UsbKeyboardDevice->RepeatTimer) {
gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
UsbKeyboardDevice->RepeatTimer = 0;
}
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
USBKeyboardRepeatHandler,
UsbKeyboardDevice,
&UsbKeyboardDevice->RepeatTimer
);
if (UsbKeyboardDevice->DelayedRecoveryEvent) {
gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
UsbKeyboardDevice->DelayedRecoveryEvent = 0;
}
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
USBKeyboardRecoveryHandler,
UsbKeyboardDevice,
&UsbKeyboardDevice->DelayedRecoveryEvent
);
return EFI_SUCCESS;
}
/**
Handler function for USB Keyboard's asynchronous interrupt transfer.
Data A pointer to a buffer that is filled with key data which is
retrieved via asynchronous interrupt transfer.
DataLength Indicates the size of the data buffer.
Context Pointing to USB_KB_DEV instance.
Result Indicates the result of the asynchronous interrupt transfer.
@retval EFI_SUCCESS Success
@retval EFI_DEVICE_ERROR Hardware Error
**/
EFI_STATUS
EFIAPI
KeyboardHandler (
IN VOID *Data,
IN UINTN DataLength,
IN VOID *Context,
IN UINT32 Result
)
{
USB_KB_DEV *UsbKeyboardDevice;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT8 *CurKeyCodeBuffer;
UINT8 *OldKeyCodeBuffer;
UINT8 CurModifierMap;
UINT8 OldModifierMap;
UINT8 Index;
UINT8 Index2;
BOOLEAN Down;
BOOLEAN KeyRelease;
BOOLEAN KeyPress;
UINT8 SavedTail;
USB_KEY UsbKey;
UINT8 NewRepeatKey;
UINT32 UsbStatus;
ASSERT (Context);
NewRepeatKey = 0;
UsbKeyboardDevice = (USB_KB_DEV *) Context;
UsbIo = UsbKeyboardDevice->UsbIo;
//
// Analyzes the Result and performs corresponding action.
//
if (Result != EFI_USB_NOERROR) {
//
// Some errors happen during the process
//
KbdReportStatusCode (
UsbKeyboardDevice->DevicePath,
EFI_ERROR_CODE | EFI_ERROR_MINOR,
PcdGet32 (PcdStatusCodeValueKeyboardInputError)
);
//
// stop the repeat key generation if any
//
UsbKeyboardDevice->RepeatKey = 0;
gBS->SetTimer (
UsbKeyboardDevice->RepeatTimer,
TimerCancel,
USBKBD_REPEAT_RATE
);
if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
UsbClearEndpointHalt (
UsbIo,
UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
&UsbStatus
);
}
//
// Delete & Submit this interrupt again
//
UsbIo->UsbAsyncInterruptTransfer (
UsbIo,
UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
FALSE,
0,
0,
NULL,
NULL
);
gBS->SetTimer (
UsbKeyboardDevice->DelayedRecoveryEvent,
TimerRelative,
EFI_USB_INTERRUPT_DELAY
);
return EFI_DEVICE_ERROR;
}
if (DataLength == 0 || Data == NULL) {
return EFI_SUCCESS;
}
CurKeyCodeBuffer = (UINT8 *) Data;
OldKeyCodeBuffer = UsbKeyboardDevice->LastKeyCodeArray;
//
// checks for new key stroke.
// if no new key got, return immediately.
//
for (Index = 0; Index < 8; Index++) {
if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) {
break;
}
}
if (Index == 8) {
return EFI_SUCCESS;
}
//
// Parse the modifier key
//
CurModifierMap = CurKeyCodeBuffer[0];
OldModifierMap = OldKeyCodeBuffer[0];
//
// handle modifier key's pressing or releasing situation.
//
for (Index = 0; Index < 8; Index++) {
if ((CurModifierMap & KB_Mod[Index].Mask) != (OldModifierMap & KB_Mod[Index].Mask)) {
//
// if current modifier key is up, then
// CurModifierMap & KB_Mod[Index].Mask = 0;
// otherwize it is a non-zero value.
// Inserts the pressed modifier key into key buffer.
//
Down = (UINT8) (CurModifierMap & KB_Mod[Index].Mask);
InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), KB_Mod[Index].Key, Down);
}
}
//
// handle normal key's releasing situation
//
KeyRelease = FALSE;
for (Index = 2; Index < 8; Index++) {
if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) {
continue;
}
KeyRelease = TRUE;
for (Index2 = 2; Index2 < 8; Index2++) {
if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index2])) {
continue;
}
if (OldKeyCodeBuffer[Index] == CurKeyCodeBuffer[Index2]) {
KeyRelease = FALSE;
break;
}
}
if (KeyRelease) {
InsertKeyCode (
&(UsbKeyboardDevice->KeyboardBuffer),
OldKeyCodeBuffer[Index],
0
);
//
// the original reapeat key is released.
//
if (OldKeyCodeBuffer[Index] == UsbKeyboardDevice->RepeatKey) {
UsbKeyboardDevice->RepeatKey = 0;
}
}
}
//
// original repeat key is released, cancel the repeat timer
//
if (UsbKeyboardDevice->RepeatKey == 0) {
gBS->SetTimer (
UsbKeyboardDevice->RepeatTimer,
TimerCancel,
USBKBD_REPEAT_RATE
);
}
//
// handle normal key's pressing situation
//
KeyPress = FALSE;
for (Index = 2; Index < 8; Index++) {
if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index])) {
continue;
}
KeyPress = TRUE;
for (Index2 = 2; Index2 < 8; Index2++) {
if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index2])) {
continue;
}
if (CurKeyCodeBuffer[Index] == OldKeyCodeBuffer[Index2]) {
KeyPress = FALSE;
break;
}
}
if (KeyPress) {
InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), CurKeyCodeBuffer[Index], 1);
//
// NumLock pressed or CapsLock pressed
//
if (CurKeyCodeBuffer[Index] == 0x53 || CurKeyCodeBuffer[Index] == 0x39) {
UsbKeyboardDevice->RepeatKey = 0;
} else {
NewRepeatKey = CurKeyCodeBuffer[Index];
//
// do not repeat the original repeated key
//
UsbKeyboardDevice->RepeatKey = 0;
}
}
}
//
// Update LastKeycodeArray[] buffer in the
// Usb Keyboard Device data structure.
//
for (Index = 0; Index < 8; Index++) {
UsbKeyboardDevice->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index];
}
//
// pre-process KeyboardBuffer, pop out the ctrl,alt,del key in sequence
// and judge whether it will invoke reset event.
//
SavedTail = UsbKeyboardDevice->KeyboardBuffer.bTail;
Index = UsbKeyboardDevice->KeyboardBuffer.bHead;
while (Index != SavedTail) {
RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey);
switch (UsbKey.KeyCode) {
case 0xe0:
case 0xe4:
if (UsbKey.Down) {
UsbKeyboardDevice->CtrlOn = 1;
} else {
UsbKeyboardDevice->CtrlOn = 0;
}
break;
case 0xe2:
case 0xe6:
if (UsbKey.Down) {
UsbKeyboardDevice->AltOn = 1;
} else {
UsbKeyboardDevice->AltOn = 0;
}
break;
//
// Del Key Code
//
case 0x4c:
case 0x63:
if (UsbKey.Down) {
if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) {
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
}
}
break;
default:
break;
}
//
// insert the key back to the buffer.
// so the key sequence will not be destroyed.
//
InsertKeyCode (
&(UsbKeyboardDevice->KeyboardBuffer),
UsbKey.KeyCode,
UsbKey.Down
);
Index = UsbKeyboardDevice->KeyboardBuffer.bHead;
}
//
// If have new key pressed, update the RepeatKey value, and set the
// timer to repeate delay timer
//
if (NewRepeatKey != 0) {
//
// sets trigger time to "Repeat Delay Time",
// to trigger the repeat timer when the key is hold long
// enough time.
//
gBS->SetTimer (
UsbKeyboardDevice->RepeatTimer,
TimerRelative,
USBKBD_REPEAT_DELAY
);
UsbKeyboardDevice->RepeatKey = NewRepeatKey;
}
return EFI_SUCCESS;
}
/**
Retrieves a key character after parsing the raw data in keyboard buffer.
UsbKeyboardDevice The USB_KB_DEV instance.
KeyChar Points to the Key character after key parsing.
@retval EFI_SUCCESS Success
@retval EFI_NOT_READY Device is not ready
**/
EFI_STATUS
USBParseKey (
IN OUT USB_KB_DEV *UsbKeyboardDevice,
OUT UINT8 *KeyChar
)
{
USB_KEY UsbKey;
*KeyChar = 0;
while (!IsUSBKeyboardBufferEmpty (&UsbKeyboardDevice->KeyboardBuffer)) {
//
// pops one raw data off.
//
RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey);
if (!UsbKey.Down) {
switch (UsbKey.KeyCode) {
//
// CTRL release
//
case 0xe0:
UsbKeyboardDevice->LeftCtrlOn = 0;
UsbKeyboardDevice->CtrlOn = 0;
break;
case 0xe4:
UsbKeyboardDevice->RightCtrlOn = 0;
UsbKeyboardDevice->CtrlOn = 0;
break;
//
// Shift release
//
case 0xe1:
UsbKeyboardDevice->LeftShiftOn = 0;
UsbKeyboardDevice->ShiftOn = 0;
break;
case 0xe5:
UsbKeyboardDevice->RightShiftOn = 0;
UsbKeyboardDevice->ShiftOn = 0;
break;
//
// Alt release
//
case 0xe2:
UsbKeyboardDevice->LeftAltOn = 0;
UsbKeyboardDevice->AltOn = 0;
break;
case 0xe6:
UsbKeyboardDevice->RightAltOn = 0;
UsbKeyboardDevice->AltOn = 0;
break;
//
// Logo release
//
case 0xe3:
UsbKeyboardDevice->LeftLogoOn = 0;
break;
case 0xe7:
UsbKeyboardDevice->RightLogoOn = 0;
break;
//
// Menu key (App/Apps) release
//
case 0x65:
UsbKeyboardDevice->MenuKeyOn = 0;
break;
//
// SysReq release
//
case 0x46:
UsbKeyboardDevice->SysReqOn = 0;
break;
default:
break;
}
continue;
}
//
// Analyzes key pressing situation
//
switch (UsbKey.KeyCode) {
case 0xe0:
UsbKeyboardDevice->LeftCtrlOn = 1;
UsbKeyboardDevice->CtrlOn = 1;
continue;
break;
case 0xe4:
UsbKeyboardDevice->RightCtrlOn = 1;
UsbKeyboardDevice->CtrlOn = 1;
continue;
break;
//
// Shift press
//
case 0xe1:
UsbKeyboardDevice->LeftShiftOn = 1;
UsbKeyboardDevice->ShiftOn = 1;
continue;
break;
case 0xe5:
UsbKeyboardDevice->RightShiftOn = 1;
UsbKeyboardDevice->ShiftOn = 1;
continue;
break;
//
// Alt press
//
case 0xe2:
UsbKeyboardDevice->LeftAltOn = 1;
UsbKeyboardDevice->AltOn = 1;
continue;
break;
case 0xe6:
UsbKeyboardDevice->RightAltOn = 1;
UsbKeyboardDevice->AltOn = 1;
continue;
break;
//
// Logo press
//
case 0xe3:
UsbKeyboardDevice->LeftLogoOn = 1;
continue;
break;
case 0xe7:
UsbKeyboardDevice->RightLogoOn = 1;
continue;
break;
//
// Menu key (App/Apps) press
//
case 0x65:
UsbKeyboardDevice->MenuKeyOn = 1;
continue;
break;
//
// SysReq press
//
case 0x46:
UsbKeyboardDevice->SysReqOn = 1;
continue;
break;
case 0x53:
UsbKeyboardDevice->NumLockOn ^= 1;
//
// Turn on the NumLock light on KB
//
SetKeyLED (UsbKeyboardDevice);
continue;
break;
case 0x39:
UsbKeyboardDevice->CapsOn ^= 1;
//
// Turn on the CapsLock light on KB
//
SetKeyLED (UsbKeyboardDevice);
continue;
break;
case 0x47:
UsbKeyboardDevice->ScrollOn ^= 1;
//
// Turn on the ScrollLock light on KB
//
SetKeyLED (UsbKeyboardDevice);
continue;
break;
//
// PrintScreen,Pause,Application,Power
// keys are not valid EFI key
//
//
// PrintScreen/SysRq key and Application key
// Should be handled by UEFI2.1 compliant code
case 0x48:
//
// fall through
//
case 0x66:
//
// fall through
//
continue;
break;
default:
break;
}
//
// When encountered Del Key...
//
if (UsbKey.KeyCode == 0x4c || UsbKey.KeyCode == 0x63) {
if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) {
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
}
}
*KeyChar = UsbKey.KeyCode;
return EFI_SUCCESS;
}
return EFI_NOT_READY;
}
/**
Converts USB Keyboard code to EFI Scan Code.
UsbKeyboardDevice The USB_KB_DEV instance.
KeyChar Indicates the key code that will be interpreted.
Key A pointer to a buffer that is filled in with
the keystroke information for the key that
was pressed.
@retval EFI_NOT_READY Device is not ready
@retval EFI_SUCCESS Success
**/
EFI_STATUS
USBKeyCodeToEFIScanCode (
IN USB_KB_DEV *UsbKeyboardDevice,
IN UINT8 KeyChar,
OUT EFI_INPUT_KEY *Key
)
{
UINT8 Index;
if (!USBKBD_VALID_KEYCODE (KeyChar)) {
return EFI_NOT_READY;
}
//
// valid USB Key Code starts from 4
//
Index = (UINT8) (KeyChar - 4);
if (Index >= USB_KEYCODE_MAX_MAKE) {
return EFI_NOT_READY;
}
//
// Undefined entries from 0x74 to 0x7E
//
if (KeyChar > USB_KEYCODE_MAX_MAKE) {
Index = (UINT8) (Index - 11);
}
Key->ScanCode = KeyConvertionTable[Index][0];
if (UsbKeyboardDevice->ShiftOn) {
Key->UnicodeChar = KeyConvertionTable[Index][2];
//
// Need not return associated shift state if a class of printable characters that
// are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
//
if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') {
UsbKeyboardDevice->LeftShiftOn = 0;
UsbKeyboardDevice->RightShiftOn = 0;
}
} else {
Key->UnicodeChar = KeyConvertionTable[Index][1];
}
if (UsbKeyboardDevice->CapsOn) {
if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') {
Key->UnicodeChar = KeyConvertionTable[Index][2];
} else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') {
Key->UnicodeChar = KeyConvertionTable[Index][1];
}
}
//
// Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
//
if (UsbKeyboardDevice->CtrlOn) {
if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') {
Key->UnicodeChar = (UINT16) (Key->UnicodeChar - 'a' + 1);
} else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') {
Key->UnicodeChar = (UINT16) (Key->UnicodeChar - 'A' + 1);
}
}
if (KeyChar >= 0x59 && KeyChar <= 0x63) {
if (UsbKeyboardDevice->NumLockOn && !UsbKeyboardDevice->ShiftOn) {
Key->ScanCode = SCAN_NULL;
} else {
Key->UnicodeChar = 0x00;
}
}
if (Key->UnicodeChar == 0 && Key->ScanCode == SCAN_NULL) {
return EFI_NOT_READY;
}
//
// Save Shift/Toggle state
//
if (UsbKeyboardDevice->LeftCtrlOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
}
if (UsbKeyboardDevice->RightCtrlOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
}
if (UsbKeyboardDevice->LeftAltOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
}
if (UsbKeyboardDevice->RightAltOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
}
if (UsbKeyboardDevice->LeftShiftOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
}
if (UsbKeyboardDevice->RightShiftOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
}
if (UsbKeyboardDevice->LeftLogoOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
}
if (UsbKeyboardDevice->RightLogoOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
}
if (UsbKeyboardDevice->MenuKeyOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_MENU_KEY_PRESSED;
}
if (UsbKeyboardDevice->SysReqOn == 1) {
UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_SYS_REQ_PRESSED;
}
if (UsbKeyboardDevice->ScrollOn == 1) {
UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
}
if (UsbKeyboardDevice->NumLockOn == 1) {
UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
}
if (UsbKeyboardDevice->CapsOn == 1) {
UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
}
return EFI_SUCCESS;
}
/**
Resets USB Keyboard Buffer.
@param KeyboardBuffer Points to the USB Keyboard Buffer.
@retval EFI_SUCCESS Success
**/
EFI_STATUS
InitUSBKeyBuffer (
IN OUT USB_KB_BUFFER *KeyboardBuffer
)
{
ZeroMem (KeyboardBuffer, sizeof (USB_KB_BUFFER));
KeyboardBuffer->bHead = KeyboardBuffer->bTail;
return EFI_SUCCESS;
}
/**
Check whether USB Keyboard buffer is empty.
@param KeyboardBuffer USB Keyboard Buffer.
**/
BOOLEAN
IsUSBKeyboardBufferEmpty (
IN USB_KB_BUFFER *KeyboardBuffer
)
{
//
// meet FIFO empty condition
//
return (BOOLEAN) (KeyboardBuffer->bHead == KeyboardBuffer->bTail);
}
/**
Check whether USB Keyboard buffer is full.
@param KeyboardBuffer USB Keyboard Buffer.
**/
BOOLEAN
IsUSBKeyboardBufferFull (
IN USB_KB_BUFFER *KeyboardBuffer
)
{
return (BOOLEAN)(((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)) ==
KeyboardBuffer->bHead);
}
/**
Inserts a key code into keyboard buffer.
@param KeyboardBuffer Points to the USB Keyboard Buffer.
@param Key Key code
@param Down Special key
@retval EFI_SUCCESS Success
**/
EFI_STATUS
InsertKeyCode (
IN OUT USB_KB_BUFFER *KeyboardBuffer,
IN UINT8 Key,
IN UINT8 Down
)
{
USB_KEY UsbKey;
//
// if keyboard buffer is full, throw the
// first key out of the keyboard buffer.
//
if (IsUSBKeyboardBufferFull (KeyboardBuffer)) {
RemoveKeyCode (KeyboardBuffer, &UsbKey);
}
KeyboardBuffer->buffer[KeyboardBuffer->bTail].KeyCode = Key;
KeyboardBuffer->buffer[KeyboardBuffer->bTail].Down = Down;
//
// adjust the tail pointer of the FIFO keyboard buffer.
//
KeyboardBuffer->bTail = (UINT8) ((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1));
return EFI_SUCCESS;
}
/**
Pops a key code off from keyboard buffer.
@param KeyboardBuffer Points to the USB Keyboard Buffer.
@param UsbKey Points to the buffer that contains a usb key code.
@retval EFI_SUCCESS Success
@retval EFI_DEVICE_ERROR Hardware Error
**/
EFI_STATUS
RemoveKeyCode (
IN OUT USB_KB_BUFFER *KeyboardBuffer,
OUT USB_KEY *UsbKey
)
{
if (IsUSBKeyboardBufferEmpty (KeyboardBuffer)) {
return EFI_DEVICE_ERROR;
}
UsbKey->KeyCode = KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode;
UsbKey->Down = KeyboardBuffer->buffer[KeyboardBuffer->bHead].Down;
//
// adjust the head pointer of the FIFO keyboard buffer.
//
KeyboardBuffer->bHead = (UINT8) ((KeyboardBuffer->bHead + 1) % (MAX_KEY_ALLOWED + 1));
return EFI_SUCCESS;
}
/**
Sets USB Keyboard LED state.
@param UsbKeyboardDevice The USB_KB_DEV instance.
@retval EFI_SUCCESS Success
**/
EFI_STATUS
SetKeyLED (
IN USB_KB_DEV *UsbKeyboardDevice
)
{
LED_MAP Led;
UINT8 ReportId;
//
// Set each field in Led map.
//
Led.NumLock = (UINT8) UsbKeyboardDevice->NumLockOn;
Led.CapsLock = (UINT8) UsbKeyboardDevice->CapsOn;
Led.ScrollLock = (UINT8) UsbKeyboardDevice->ScrollOn;
Led.Resrvd = 0;
ReportId = 0;
//
// call Set Report Request to lighten the LED.
//
UsbSetReportRequest (
UsbKeyboardDevice->UsbIo,
UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
ReportId,
HID_OUTPUT_REPORT,
1,
(UINT8 *) &Led
);
return EFI_SUCCESS;
}
/**
Timer handler for Repeat Key timer.
@param Event The Repeat Key event.
@param Context Points to the USB_KB_DEV instance.
**/
VOID
EFIAPI
USBKeyboardRepeatHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
USB_KB_DEV *UsbKeyboardDevice;
UsbKeyboardDevice = (USB_KB_DEV *) Context;
//
// Do nothing when there is no repeat key.
//
if (UsbKeyboardDevice->RepeatKey != 0) {
//
// Inserts one Repeat key into keyboard buffer,
//
InsertKeyCode (
&(UsbKeyboardDevice->KeyboardBuffer),
UsbKeyboardDevice->RepeatKey,
1
);
//
// set repeate rate for repeat key generation.
//
gBS->SetTimer (
UsbKeyboardDevice->RepeatTimer,
TimerRelative,
USBKBD_REPEAT_RATE
);
}
}
/**
Timer handler for Delayed Recovery timer.
@param Event The Delayed Recovery event.
@param Context Points to the USB_KB_DEV instance.
**/
VOID
EFIAPI
USBKeyboardRecoveryHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
USB_KB_DEV *UsbKeyboardDevice;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT8 PacketSize;
UsbKeyboardDevice = (USB_KB_DEV *) Context;
UsbIo = UsbKeyboardDevice->UsbIo;
PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
UsbIo->UsbAsyncInterruptTransfer (
UsbIo,
UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
TRUE,
UsbKeyboardDevice->IntEndpointDescriptor.Interval,
PacketSize,
KeyboardHandler,
UsbKeyboardDevice
);
}