📄 keyboard.c
字号:
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
Keyboard.c
Abstract:
Helper functions for USB Keyboard Driver
Revision History
--*/
#include "keyboard.h"
#include "hid.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_NULL, 0x00, 0x00, // 0x44 F11
SCAN_NULL, 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 =
};
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
};
BOOLEAN
IsUSBKeyboard(
IN EFI_USB_IO_PROTOCOL *UsbIo
)
/*++
Routine Description:
Uses USB I/O to check whether the device is a USB Keyboard device.
Arguments:
UsbIo: Points to a USB I/O protocol instance.
Returns:
--*/
{
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;
}
EFI_STATUS
InitUSBKeyboard(
IN USB_KB_DEV *UsbKeyboardDevice
)
/*++
Routine Description:
Initialize USB Keyboard device and all private data structures.
Arguments:
UsbKeyboardDevice: The USB_KB_DEV instance.
Returns:
--*/
{
UINT8 ConfigValue;
UINT8 Protocol;
UINT8 ReportId;
UINT8 Duration;
EFI_STATUS Status;
UINT32 TransferResult;
InitUSBKeyBuffer(&(UsbKeyboardDevice->KeyboardBuffer));
ConfigValue = 0x01; // default configurations
//
// Uses default configuration to configure the USB Keyboard device.
//
Status = UsbSetDeviceConfiguration (
UsbKeyboardDevice->UsbIo,
(UINT16)ConfigValue,
&TransferResult
);
if(EFI_ERROR(Status)) {
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.
//
ReportId = 0; // idle value for all report ID
Duration = 0; // idle forever until there is a key pressed and released.
UsbSetIdleRequest(
UsbKeyboardDevice->UsbIo,
UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,
ReportId,
Duration
);
UsbKeyboardDevice->CtrlOn = 0;
UsbKeyboardDevice->AltOn = 0;
UsbKeyboardDevice->ShiftOn = 0;
UsbKeyboardDevice->NumLockOn = 0 ;
UsbKeyboardDevice->CapsOn = 0 ;
EfiZeroMem(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 (
EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
EFI_TPL_NOTIFY,
USBKeyboardRepeatHandler,
UsbKeyboardDevice,
&UsbKeyboardDevice->RepeatTimer
) ;
return EFI_SUCCESS;
}
EFI_STATUS
KeyboardHandler(
IN VOID *Data,
IN UINTN DataLength,
IN VOID *Context,
IN UINT32 Result
)
/*++
Routine Description:
Handler function for USB Keyboard's asynchronous interrupt transfer.
Arguments:
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.
Returns:
--*/
{
USB_KB_DEV *UsbKeyboardDevice;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT8 *CurKeyCodeBuffer;
UINT8 *OldKeyCodeBuffer;
UINT8 CurModifierMap;
UINT8 OldModifierMap;
UINT8 i;
UINT8 j;
BOOLEAN Down;
EFI_STATUS Status;
BOOLEAN KeyRelease,KeyPress;
UINT8 SavedTail;
USB_KEY UsbKey;
UINT8 NewRepeatKey = 0;
UINT32 UsbStatus;
UINT8 PacketSize;
UsbKeyboardDevice = (USB_KB_DEV*)Context;
ASSERT(UsbKeyboardDevice);
UsbIo = UsbKeyboardDevice->UsbIo;
//
// Analyzes the Result and performs corresponding action.
//
if (Result != EFI_USB_NOERROR) {
//
// 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
//
Status = UsbIo->UsbAsyncInterruptTransfer(
UsbIo,
UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
FALSE,
0,
0,
NULL,
NULL
);
PacketSize = (UINT8)(UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
Status = UsbIo->UsbAsyncInterruptTransfer(
UsbIo,
UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
TRUE,
UsbKeyboardDevice->IntEndpointDescriptor.Interval,
PacketSize,
KeyboardHandler,
UsbKeyboardDevice
);
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 (i = 0; i < 8; i ++) {
if(OldKeyCodeBuffer[i] != CurKeyCodeBuffer[i]) {
break;
}
}
if(i == 8) {
return EFI_SUCCESS;
}
//
// Parse the modifier key
//
CurModifierMap = CurKeyCodeBuffer[0];
OldModifierMap = OldKeyCodeBuffer[0];
//
// handle modifier key's pressing or releasing situation.
//
for (i = 0; i < 8; i ++) {
if ((CurModifierMap & KB_Mod[i].Mask) !=
(OldModifierMap & KB_Mod[i].Mask)) {
//
// if current modifier key is up, then
// CurModifierMap & KB_Mod[i].Mask = 0;
// otherwize it is a non-zero value.
// Inserts the pressed modifier key into key buffer.
//
Down = (UINT8)(CurModifierMap & KB_Mod[i].Mask);
InsertKeyCode(&(UsbKeyboardDevice->KeyboardBuffer),KB_Mod[i].Key,Down);
}
}
//
// handle normal key's releasing situation
//
KeyRelease = FALSE;
for (i = 2; i < 8; i ++) {
if(!USBKBD_VALID_KEYCODE(OldKeyCodeBuffer[i])) {
continue;
}
KeyRelease = TRUE;
for (j = 2; j < 8; j ++) {
if(!USBKBD_VALID_KEYCODE(CurKeyCodeBuffer[j])) {
continue;
}
if (OldKeyCodeBuffer[i] == CurKeyCodeBuffer[j]) {
KeyRelease = FALSE;
break;
}
}
if (KeyRelease) {
InsertKeyCode(&(UsbKeyboardDevice->KeyboardBuffer),OldKeyCodeBuffer[i],0);
//
// the original reapeat key is released.
//
if (OldKeyCodeBuffer[i] == 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 (i = 2; i < 8; i ++) {
if(!USBKBD_VALID_KEYCODE(CurKeyCodeBuffer[i])) {
continue;
}
KeyPress = TRUE;
for (j = 2; j < 8; j ++) {
if(!USBKBD_VALID_KEYCODE(OldKeyCodeBuffer[j])) {
continue;
}
if (CurKeyCodeBuffer[i] == OldKeyCodeBuffer[j]) {
KeyPress = FALSE;
break;
}
}
if(KeyPress) {
InsertKeyCode(&(UsbKeyboardDevice->KeyboardBuffer),CurKeyCodeBuffer[i],1);
//
// NumLock pressed or CapsLock pressed
//
if(CurKeyCodeBuffer[i] == 0x53 || CurKeyCodeBuffer[i] == 0x39) {
UsbKeyboardDevice->RepeatKey = 0;
} else {
NewRepeatKey = CurKeyCodeBuffer[i];
//
// do not repeat the original repeated key
//
UsbKeyboardDevice->RepeatKey = 0;
}
}
}
//
// Update LastKeycodeArray[] buffer in the
// Usb Keyboard Device data structure.
//
for (i = 0; i < 8; i ++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -