[Description]
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Bus / Usb / UsbKbDxe / keyboard.c
1 /** @file\r
2 \r
3 Copyright (c) 2004 - 2008, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   Keyboard.c\r
15 \r
16 Abstract:\r
17 \r
18   Helper functions for USB Keyboard Driver\r
19 \r
20 Revision History\r
21 \r
22 \r
23 **/\r
24 \r
25 #include "keyboard.h"\r
26 #include <Library/UsbLib.h>\r
27 \r
28 //\r
29 // Static English keyboard layout\r
30 // Format:<efi key>, <unicode without shift>, <unicode with shift>, <Modifier>, <AffectedAttribute>\r
31 //\r
32 STATIC\r
33 UINT8 KeyboardLayoutTable[USB_KEYCODE_MAX_MAKE + 8][5] = {\r
34   {EfiKeyC1,         'a',      'A',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x04\r
35   {EfiKeyB5,         'b',      'B',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x05\r
36   {EfiKeyB3,         'c',      'C',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x06\r
37   {EfiKeyC3,         'd',      'D',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x07\r
38   {EfiKeyD3,         'e',      'E',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x08\r
39   {EfiKeyC4,         'f',      'F',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x09\r
40   {EfiKeyC5,         'g',      'G',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0A\r
41   {EfiKeyC6,         'h',      'H',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0B\r
42   {EfiKeyD8,         'i',      'I',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0C\r
43   {EfiKeyC7,         'j',      'J',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0D\r
44   {EfiKeyC8,         'k',      'K',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0E\r
45   {EfiKeyC9,         'l',      'L',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x0F\r
46   {EfiKeyB7,         'm',      'M',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x10\r
47   {EfiKeyB6,         'n',      'N',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x11\r
48   {EfiKeyD9,         'o',      'O',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x12\r
49   {EfiKeyD10,        'p',      'P',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x13\r
50   {EfiKeyD1,         'q',      'Q',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x14\r
51   {EfiKeyD4,         'r',      'R',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x15\r
52   {EfiKeyC2,         's',      'S',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x16\r
53   {EfiKeyD5,         't',      'T',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x17\r
54   {EfiKeyD7,         'u',      'U',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x18\r
55   {EfiKeyB4,         'v',      'V',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x19\r
56   {EfiKeyD2,         'w',      'W',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x1A\r
57   {EfiKeyB2,         'x',      'X',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x1B\r
58   {EfiKeyD6,         'y',      'Y',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x1C\r
59   {EfiKeyB1,         'z',      'Z',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_CAPS_LOCK},   // 0x1D\r
60   {EfiKeyE1,         '1',      '!',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x1E\r
61   {EfiKeyE2,         '2',      '@',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x1F\r
62   {EfiKeyE3,         '3',      '#',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x20\r
63   {EfiKeyE4,         '4',      '$',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x21\r
64   {EfiKeyE5,         '5',      '%',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x22\r
65   {EfiKeyE6,         '6',      '^',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x23\r
66   {EfiKeyE7,         '7',      '&',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x24\r
67   {EfiKeyE8,         '8',      '*',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x25\r
68   {EfiKeyE9,         '9',      '(',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x26\r
69   {EfiKeyE10,        '0',      ')',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x27\r
70   {EfiKeyEnter,      0x0d,     0x0d,  EFI_NULL_MODIFIER,   0},                                // 0x28   Enter\r
71   {EfiKeyEsc,        0x1b,     0x1b,  EFI_NULL_MODIFIER,   0},                                // 0x29   Esc\r
72   {EfiKeyBackSpace,  0x08,     0x08,  EFI_NULL_MODIFIER,   0},                                // 0x2A   Backspace\r
73   {EfiKeyTab,        0x09,     0x09,  EFI_NULL_MODIFIER,   0},                                // 0x2B   Tab\r
74   {EfiKeySpaceBar,   ' ',      ' ',   EFI_NULL_MODIFIER,   0},                                // 0x2C   Spacebar\r
75   {EfiKeyE11,        '-',      '_',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x2D\r
76   {EfiKeyE12,        '=',      '+',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x2E\r
77   {EfiKeyD11,        '[',      '{',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x2F\r
78   {EfiKeyD12,        ']',      '}',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x30\r
79   {EfiKeyD13,        '\\',     '|',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x31\r
80   {EfiKeyC12,        '\\',     '|',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x32  Keyboard Non-US # and ~\r
81   {EfiKeyC10,        ';',      ':',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x33\r
82   {EfiKeyC11,        '\'',     '"',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x34\r
83   {EfiKeyE0,         '`',      '~',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x35  Keyboard Grave Accent and Tlide\r
84   {EfiKeyB8,         ',',      '<',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x36\r
85   {EfiKeyB9,         '.',      '>',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x37\r
86   {EfiKeyB10,        '/',      '?',   EFI_NULL_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT},   // 0x38\r
87   {EfiKeyCapsLock,   0x00,     0x00,  EFI_CAPS_LOCK_MODIFIER,            0},                  // 0x39   CapsLock\r
88   {EfiKeyF1,         0x00,     0x00,  EFI_FUNCTION_KEY_ONE_MODIFIER,     0},                  // 0x3A\r
89   {EfiKeyF2,         0x00,     0x00,  EFI_FUNCTION_KEY_TWO_MODIFIER,     0},                  // 0x3B\r
90   {EfiKeyF3,         0x00,     0x00,  EFI_FUNCTION_KEY_THREE_MODIFIER,   0},                  // 0x3C\r
91   {EfiKeyF4,         0x00,     0x00,  EFI_FUNCTION_KEY_FOUR_MODIFIER,    0},                  // 0x3D\r
92   {EfiKeyF5,         0x00,     0x00,  EFI_FUNCTION_KEY_FIVE_MODIFIER,    0},                  // 0x3E\r
93   {EfiKeyF6,         0x00,     0x00,  EFI_FUNCTION_KEY_SIX_MODIFIER,     0},                  // 0x3F\r
94   {EfiKeyF7,         0x00,     0x00,  EFI_FUNCTION_KEY_SEVEN_MODIFIER,   0},                  // 0x40\r
95   {EfiKeyF8,         0x00,     0x00,  EFI_FUNCTION_KEY_EIGHT_MODIFIER,   0},                  // 0x41\r
96   {EfiKeyF9,         0x00,     0x00,  EFI_FUNCTION_KEY_NINE_MODIFIER,    0},                  // 0x42\r
97   {EfiKeyF10,        0x00,     0x00,  EFI_FUNCTION_KEY_TEN_MODIFIER,     0},                  // 0x43\r
98   {EfiKeyF11,        0x00,     0x00,  EFI_FUNCTION_KEY_ELEVEN_MODIFIER,  0},                  // 0x44   F11\r
99   {EfiKeyF12,        0x00,     0x00,  EFI_FUNCTION_KEY_TWELVE_MODIFIER,  0},                  // 0x45   F12\r
100   {EfiKeyPrint,      0x00,     0x00,  EFI_PRINT_MODIFIER,                0},                  // 0x46   PrintScreen\r
101   {EfiKeySLck,       0x00,     0x00,  EFI_SCROLL_LOCK_MODIFIER,          0},                  // 0x47   Scroll Lock\r
102   {EfiKeyPause,      0x00,     0x00,  EFI_PAUSE_MODIFIER,                0},                  // 0x48   Pause\r
103   {EfiKeyIns,        0x00,     0x00,  EFI_INSERT_MODIFIER,               0},                  // 0x49\r
104   {EfiKeyHome,       0x00,     0x00,  EFI_HOME_MODIFIER,                 0},                  // 0x4A\r
105   {EfiKeyPgUp,       0x00,     0x00,  EFI_PAGE_UP_MODIFIER,              0},                  // 0x4B\r
106   {EfiKeyDel,        0x00,     0x00,  EFI_DELETE_MODIFIER,               0},                  // 0x4C\r
107   {EfiKeyEnd,        0x00,     0x00,  EFI_END_MODIFIER,                  0},                  // 0x4D\r
108   {EfiKeyPgDn,       0x00,     0x00,  EFI_PAGE_DOWN_MODIFIER,            0},                  // 0x4E\r
109   {EfiKeyRightArrow, 0x00,     0x00,  EFI_RIGHT_ARROW_MODIFIER,          0},                  // 0x4F\r
110   {EfiKeyLeftArrow,  0x00,     0x00,  EFI_LEFT_ARROW_MODIFIER,           0},                  // 0x50\r
111   {EfiKeyDownArrow,  0x00,     0x00,  EFI_DOWN_ARROW_MODIFIER,           0},                  // 0x51\r
112   {EfiKeyUpArrow,    0x00,     0x00,  EFI_UP_ARROW_MODIFIER,             0},                  // 0x52\r
113   {EfiKeyNLck,       0x00,     0x00,  EFI_NUM_LOCK_MODIFIER,             0},                  // 0x53   NumLock\r
114   {EfiKeySlash,      '/',      '/',   EFI_NULL_MODIFIER,                 0},                  // 0x54\r
115   {EfiKeyAsterisk,   '*',      '*',   EFI_NULL_MODIFIER,                 0},                  // 0x55\r
116   {EfiKeyMinus,      '-',      '-',   EFI_NULL_MODIFIER,                 0},                  // 0x56\r
117   {EfiKeyPlus,       '+',      '+',   EFI_NULL_MODIFIER,                 0},                  // 0x57\r
118   {EfiKeyEnter,      0x0d,     0x0d,  EFI_NULL_MODIFIER,                 0},                  // 0x58\r
119   {EfiKeyOne,        '1',      '1',   EFI_END_MODIFIER,         EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x59\r
120   {EfiKeyTwo,        '2',      '2',   EFI_DOWN_ARROW_MODIFIER,  EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5A\r
121   {EfiKeyThree,      '3',      '3',   EFI_PAGE_DOWN_MODIFIER,   EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5B\r
122   {EfiKeyFour,       '4',      '4',   EFI_LEFT_ARROW_MODIFIER,  EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5C\r
123   {EfiKeyFive,       '5',      '5',   EFI_NULL_MODIFIER,        EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5D\r
124   {EfiKeySix,        '6',      '6',   EFI_RIGHT_ARROW_MODIFIER, EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5E\r
125   {EfiKeySeven,      '7',      '7',   EFI_HOME_MODIFIER,        EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x5F\r
126   {EfiKeyEight,      '8',      '8',   EFI_UP_ARROW_MODIFIER,    EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x60\r
127   {EfiKeyNine,       '9',      '9',   EFI_PAGE_UP_MODIFIER,     EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x61\r
128   {EfiKeyZero,       '0',      '0',   EFI_INSERT_MODIFIER,      EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x62\r
129   {EfiKeyPeriod,     '.',      '.',   EFI_DELETE_MODIFIER,      EFI_AFFECTED_BY_STANDARD_SHIFT | EFI_AFFECTED_BY_NUM_LOCK},   // 0x63\r
130   {EfiKeyB0,         '\\',     '|',   EFI_NULL_MODIFIER,        EFI_AFFECTED_BY_STANDARD_SHIFT}, // 0x64 Keyboard Non-US \ and |\r
131   {EfiKeyA4,         0x00,     0x00,  EFI_MENU_MODIFIER,        0},                              // 0x65 Keyboard Application\r
132 \r
133   {EfiKeyLCtrl,      0,        0,     EFI_LEFT_CONTROL_MODIFIER,    0},  // 0xe0\r
134   {EfiKeyLShift,     0,        0,     EFI_LEFT_SHIFT_MODIFIER,      0},  // 0xe1\r
135   {EfiKeyLAlt,       0,        0,     EFI_LEFT_ALT_MODIFIER,        0},  // 0xe2\r
136   {EfiKeyA0,         0,        0,     EFI_LEFT_LOGO_MODIFIER,       0},  // 0xe3\r
137   {EfiKeyRCtrl,      0,        0,     EFI_RIGHT_CONTROL_MODIFIER,   0},  // 0xe4\r
138   {EfiKeyRShift,     0,        0,     EFI_RIGHT_SHIFT_MODIFIER,     0},  // 0xe5\r
139   {EfiKeyA2,         0,        0,     EFI_RIGHT_ALT_MODIFIER,       0},  // 0xe6\r
140   {EfiKeyA3,         0,        0,     EFI_RIGHT_LOGO_MODIFIER,      0},  // 0xe7\r
141 };\r
142 \r
143 VOID\r
144 LoadDefaultKeyboardLayout (\r
145   IN USB_KB_DEV                 *UsbKeyboardDevice\r
146   )\r
147 /*++\r
148 \r
149   Routine Description:\r
150     Initialize KeyConvertionTable by using default keyboard layout.\r
151 \r
152   Arguments:\r
153     UsbKeyboardDevice    The USB_KB_DEV instance.\r
154 \r
155   Returns:\r
156     None.\r
157 \r
158 --*/\r
159 {\r
160   UINTN               Index;\r
161   EFI_KEY_DESCRIPTOR  *KeyDescriptor;\r
162 \r
163   //\r
164   // Construct KeyConvertionTable by default keyboard layout\r
165   //\r
166   KeyDescriptor = &UsbKeyboardDevice->KeyConvertionTable[0];\r
167 \r
168   for (Index = 0; Index < (USB_KEYCODE_MAX_MAKE + 8); Index++) {\r
169     KeyDescriptor->Key                 = (EFI_KEY) KeyboardLayoutTable[Index][0];\r
170     KeyDescriptor->Unicode             = KeyboardLayoutTable[Index][1];\r
171     KeyDescriptor->ShiftedUnicode      = KeyboardLayoutTable[Index][2];\r
172     KeyDescriptor->AltGrUnicode        = 0;\r
173     KeyDescriptor->ShiftedAltGrUnicode = 0;\r
174     KeyDescriptor->Modifier            = KeyboardLayoutTable[Index][3];\r
175     KeyDescriptor->AffectedAttribute   = KeyboardLayoutTable[Index][4];\r
176 \r
177     KeyDescriptor++;\r
178   }\r
179 }\r
180 \r
181 //\r
182 // EFI_KEY to USB Scan Code convertion table\r
183 //\r
184 STATIC\r
185 UINT8 UsbScanCodeConvertionTable[] = {\r
186   0xe0,  //  EfiKeyLCtrl\r
187   0xe3,  //  EfiKeyA0\r
188   0xe2,  //  EfiKeyLAlt\r
189   0x2c,  //  EfiKeySpaceBar\r
190   0xe6,  //  EfiKeyA2\r
191   0xe7,  //  EfiKeyA3\r
192   0x65,  //  EfiKeyA4\r
193   0xe4,  //  EfiKeyRCtrl\r
194   0x50,  //  EfiKeyLeftArrow\r
195   0x51,  //  EfiKeyDownArrow\r
196   0x4F,  //  EfiKeyRightArrow\r
197   0x62,  //  EfiKeyZero\r
198   0x63,  //  EfiKeyPeriod\r
199   0x28,  //  EfiKeyEnter\r
200   0xe1,  //  EfiKeyLShift\r
201   0x64,  //  EfiKeyB0\r
202   0x1D,  //  EfiKeyB1\r
203   0x1B,  //  EfiKeyB2\r
204   0x06,  //  EfiKeyB3\r
205   0x19,  //  EfiKeyB4\r
206   0x05,  //  EfiKeyB5\r
207   0x11,  //  EfiKeyB6\r
208   0x10,  //  EfiKeyB7\r
209   0x36,  //  EfiKeyB8\r
210   0x37,  //  EfiKeyB9\r
211   0x38,  //  EfiKeyB10\r
212   0xe5,  //  EfiKeyRShift\r
213   0x52,  //  EfiKeyUpArrow\r
214   0x59,  //  EfiKeyOne\r
215   0x5A,  //  EfiKeyTwo\r
216   0x5B,  //  EfiKeyThree\r
217   0x39,  //  EfiKeyCapsLock\r
218   0x04,  //  EfiKeyC1\r
219   0x16,  //  EfiKeyC2\r
220   0x07,  //  EfiKeyC3\r
221   0x09,  //  EfiKeyC4\r
222   0x0A,  //  EfiKeyC5\r
223   0x0B,  //  EfiKeyC6\r
224   0x0D,  //  EfiKeyC7\r
225   0x0E,  //  EfiKeyC8\r
226   0x0F,  //  EfiKeyC9\r
227   0x33,  //  EfiKeyC10\r
228   0x34,  //  EfiKeyC11\r
229   0x32,  //  EfiKeyC12\r
230   0x5C,  //  EfiKeyFour\r
231   0x5D,  //  EfiKeyFive\r
232   0x5E,  //  EfiKeySix\r
233   0x57,  //  EfiKeyPlus\r
234   0x2B,  //  EfiKeyTab\r
235   0x14,  //  EfiKeyD1\r
236   0x1A,  //  EfiKeyD2\r
237   0x08,  //  EfiKeyD3\r
238   0x15,  //  EfiKeyD4\r
239   0x17,  //  EfiKeyD5\r
240   0x1C,  //  EfiKeyD6\r
241   0x18,  //  EfiKeyD7\r
242   0x0C,  //  EfiKeyD8\r
243   0x12,  //  EfiKeyD9\r
244   0x13,  //  EfiKeyD10\r
245   0x2F,  //  EfiKeyD11\r
246   0x30,  //  EfiKeyD12\r
247   0x31,  //  EfiKeyD13\r
248   0x4C,  //  EfiKeyDel\r
249   0x4D,  //  EfiKeyEnd\r
250   0x4E,  //  EfiKeyPgDn\r
251   0x5F,  //  EfiKeySeven\r
252   0x60,  //  EfiKeyEight\r
253   0x61,  //  EfiKeyNine\r
254   0x35,  //  EfiKeyE0\r
255   0x1E,  //  EfiKeyE1\r
256   0x1F,  //  EfiKeyE2\r
257   0x20,  //  EfiKeyE3\r
258   0x21,  //  EfiKeyE4\r
259   0x22,  //  EfiKeyE5\r
260   0x23,  //  EfiKeyE6\r
261   0x24,  //  EfiKeyE7\r
262   0x25,  //  EfiKeyE8\r
263   0x26,  //  EfiKeyE9\r
264   0x27,  //  EfiKeyE10\r
265   0x2D,  //  EfiKeyE11\r
266   0x2E,  //  EfiKeyE12\r
267   0x2A,  //  EfiKeyBackSpace\r
268   0x49,  //  EfiKeyIns\r
269   0x4A,  //  EfiKeyHome\r
270   0x4B,  //  EfiKeyPgUp\r
271   0x53,  //  EfiKeyNLck\r
272   0x54,  //  EfiKeySlash\r
273   0x55,  //  EfiKeyAsterisk\r
274   0x56,  //  EfiKeyMinus\r
275   0x29,  //  EfiKeyEsc\r
276   0x3A,  //  EfiKeyF1\r
277   0x3B,  //  EfiKeyF2\r
278   0x3C,  //  EfiKeyF3\r
279   0x3D,  //  EfiKeyF4\r
280   0x3E,  //  EfiKeyF5\r
281   0x3F,  //  EfiKeyF6\r
282   0x40,  //  EfiKeyF7\r
283   0x41,  //  EfiKeyF8\r
284   0x42,  //  EfiKeyF9\r
285   0x43,  //  EfiKeyF10\r
286   0x44,  //  EfiKeyF11\r
287   0x45,  //  EfiKeyF12\r
288   0x46,  //  EfiKeyPrint\r
289   0x47,  //  EfiKeySLck\r
290   0x48   //  EfiKeyPause\r
291 };\r
292 \r
293 //\r
294 // Keyboard Layout Modifier to EFI Scan Code convertion table\r
295 //\r
296 STATIC\r
297 UINT8 EfiScanCodeConvertionTable[] = {\r
298   SCAN_NULL,       // EFI_NULL_MODIFIER\r
299   SCAN_NULL,       // EFI_LEFT_CONTROL_MODIFIER\r
300   SCAN_NULL,       // EFI_RIGHT_CONTROL_MODIFIER\r
301   SCAN_NULL,       // EFI_LEFT_ALT_MODIFIER\r
302   SCAN_NULL,       // EFI_RIGHT_ALT_MODIFIER\r
303   SCAN_NULL,       // EFI_ALT_GR_MODIFIER\r
304   SCAN_INSERT,     // EFI_INSERT_MODIFIER\r
305   SCAN_DELETE,     // EFI_DELETE_MODIFIER\r
306   SCAN_PAGE_DOWN,  // EFI_PAGE_DOWN_MODIFIER\r
307   SCAN_PAGE_UP,    // EFI_PAGE_UP_MODIFIER\r
308   SCAN_HOME,       // EFI_HOME_MODIFIER\r
309   SCAN_END,        // EFI_END_MODIFIER\r
310   SCAN_NULL,       // EFI_LEFT_SHIFT_MODIFIER\r
311   SCAN_NULL,       // EFI_RIGHT_SHIFT_MODIFIER\r
312   SCAN_NULL,       // EFI_CAPS_LOCK_MODIFIER\r
313   SCAN_NULL,       // EFI_NUM_LOCK_MODIFIER\r
314   SCAN_LEFT,       // EFI_LEFT_ARROW_MODIFIER\r
315   SCAN_RIGHT,      // EFI_RIGHT_ARROW_MODIFIER\r
316   SCAN_DOWN,       // EFI_DOWN_ARROW_MODIFIER\r
317   SCAN_UP,         // EFI_UP_ARROW_MODIFIER\r
318   SCAN_NULL,       // EFI_NS_KEY_MODIFIER\r
319   SCAN_NULL,       // EFI_NS_KEY_DEPENDENCY_MODIFIER\r
320   SCAN_F1,         // EFI_FUNCTION_KEY_ONE_MODIFIER\r
321   SCAN_F2,         // EFI_FUNCTION_KEY_TWO_MODIFIER\r
322   SCAN_F3,         // EFI_FUNCTION_KEY_THREE_MODIFIER\r
323   SCAN_F4,         // EFI_FUNCTION_KEY_FOUR_MODIFIER\r
324   SCAN_F5,         // EFI_FUNCTION_KEY_FIVE_MODIFIER\r
325   SCAN_F6,         // EFI_FUNCTION_KEY_SIX_MODIFIER\r
326   SCAN_F7,         // EFI_FUNCTION_KEY_SEVEN_MODIFIER\r
327   SCAN_F8,         // EFI_FUNCTION_KEY_EIGHT_MODIFIER\r
328   SCAN_F9,         // EFI_FUNCTION_KEY_NINE_MODIFIER\r
329   SCAN_F10,        // EFI_FUNCTION_KEY_TEN_MODIFIER\r
330   SCAN_F11,        // EFI_FUNCTION_KEY_ELEVEN_MODIFIER\r
331   SCAN_F12,        // EFI_FUNCTION_KEY_TWELVE_MODIFIER\r
332 };\r
333 \r
334 EFI_GUID  mKeyboardLayoutEventGuid = EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID;\r
335 \r
336 \r
337 STATIC KB_MODIFIER  KB_Mod[8] = {\r
338   { MOD_CONTROL_L,  0xe0 }, // 11100000\r
339   { MOD_CONTROL_R,  0xe4 }, // 11100100\r
340   { MOD_SHIFT_L,    0xe1 }, // 11100001\r
341   { MOD_SHIFT_R,    0xe5 }, // 11100101\r
342   { MOD_ALT_L,      0xe2 }, // 11100010\r
343   { MOD_ALT_R,      0xe6 }, // 11100110\r
344   { MOD_WIN_L,      0xe3 }, // 11100011\r
345   { MOD_WIN_R,      0xe7 }, // 11100111 \r
346 };\r
347 \r
348 \r
349 \r
350 /**\r
351   Uses USB I/O to check whether the device is a USB Keyboard device.\r
352 \r
353   UsbIo:    Points to a USB I/O protocol instance.\r
354 \r
355 \r
356 **/\r
357 BOOLEAN\r
358 IsUSBKeyboard (\r
359   IN  EFI_USB_IO_PROTOCOL       *UsbIo\r
360   )\r
361 {\r
362   EFI_STATUS                    Status;\r
363   EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;\r
364 \r
365   //\r
366   // Get the Default interface descriptor, currently we\r
367   // assume it is interface 1\r
368   //\r
369   Status = UsbIo->UsbGetInterfaceDescriptor (\r
370                     UsbIo,\r
371                     &InterfaceDescriptor\r
372                     );\r
373 \r
374   if (EFI_ERROR (Status)) {\r
375     return FALSE;\r
376   }\r
377 \r
378   if (InterfaceDescriptor.InterfaceClass == CLASS_HID &&\r
379       InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT &&\r
380       InterfaceDescriptor.InterfaceProtocol == PROTOCOL_KEYBOARD\r
381       ) {\r
382 \r
383     return TRUE;\r
384   }\r
385 \r
386   return FALSE;\r
387 }\r
388 \r
389 \r
390 EFI_HII_KEYBOARD_LAYOUT *\r
391 GetCurrentKeyboardLayout (\r
392   VOID\r
393   )\r
394 /*++\r
395 \r
396   Routine Description:\r
397     Get current keyboard layout from HII database.\r
398 \r
399   Arguments:\r
400     None.\r
401 \r
402   Returns:\r
403     Pointer to EFI_HII_KEYBOARD_LAYOUT.\r
404 \r
405 --*/\r
406 {\r
407   EFI_STATUS                Status;\r
408   EFI_HII_DATABASE_PROTOCOL *HiiDatabase;\r
409   EFI_HII_KEYBOARD_LAYOUT   *KeyboardLayout;\r
410   UINT16                    Length;\r
411 \r
412   //\r
413   // Locate Hii database protocol\r
414   //\r
415   Status = gBS->LocateProtocol (\r
416                   &gEfiHiiDatabaseProtocolGuid,\r
417                   NULL,\r
418                   (VOID **) &HiiDatabase\r
419                   );\r
420   if (EFI_ERROR (Status)) {\r
421     return NULL;\r
422   }\r
423 \r
424   //\r
425   // Get current keyboard layout from HII database\r
426   //\r
427   Length = 0;\r
428   KeyboardLayout = NULL;\r
429   Status = HiiDatabase->GetKeyboardLayout (\r
430                           HiiDatabase,\r
431                           NULL,\r
432                           &Length,\r
433                           KeyboardLayout\r
434                           );\r
435   if (Status == EFI_BUFFER_TOO_SMALL) {\r
436     KeyboardLayout = AllocatePool (Length);\r
437     ASSERT (KeyboardLayout != NULL);\r
438 \r
439     Status = HiiDatabase->GetKeyboardLayout (\r
440                             HiiDatabase,\r
441                             NULL,\r
442                             &Length,\r
443                             KeyboardLayout\r
444                             );\r
445     if (EFI_ERROR (Status)) {\r
446       gBS->FreePool (KeyboardLayout);\r
447       KeyboardLayout = NULL;\r
448     }\r
449   }\r
450 \r
451   return KeyboardLayout;\r
452 }\r
453 \r
454 EFI_KEY_DESCRIPTOR *\r
455 GetKeyDescriptor (\r
456   IN USB_KB_DEV        *UsbKeyboardDevice,\r
457   IN UINT8             ScanCode\r
458   )\r
459 /*++\r
460 \r
461   Routine Description:\r
462     Find Key Descriptor in KeyConvertionTable given its scan code.\r
463 \r
464   Arguments:\r
465     UsbKeyboardDevice  -  The USB_KB_DEV instance.\r
466     ScanCode           -  USB scan code.\r
467 \r
468   Returns:\r
469     The Key descriptor in KeyConvertionTable.\r
470 \r
471 --*/\r
472 {\r
473   UINT8  Index;\r
474 \r
475   if (((ScanCode > 0x65) && (ScanCode < 0xe0)) || (ScanCode > 0xe7)) {\r
476     return NULL;\r
477   }\r
478 \r
479   if (ScanCode <= 0x65) {\r
480     Index = (UINT8) (ScanCode - 4);\r
481   } else {\r
482     Index = (UINT8) (ScanCode - 0xe0 + USB_KEYCODE_MAX_MAKE);\r
483   }\r
484 \r
485   return &UsbKeyboardDevice->KeyConvertionTable[Index];\r
486 }\r
487 \r
488 USB_NS_KEY *\r
489 FindUsbNsKey (\r
490   IN USB_KB_DEV          *UsbKeyboardDevice,\r
491   IN EFI_KEY_DESCRIPTOR  *KeyDescriptor\r
492   )\r
493 /*++\r
494 \r
495   Routine Description:\r
496     Find Non-Spacing key for given KeyDescriptor.\r
497 \r
498   Arguments:\r
499     UsbKeyboardDevice  -  The USB_KB_DEV instance.\r
500     KeyDescriptor      -  Key descriptor.\r
501 \r
502   Returns:\r
503     The Non-Spacing key.\r
504 \r
505 --*/\r
506 {\r
507   LIST_ENTRY      *Link;\r
508   USB_NS_KEY      *UsbNsKey;\r
509 \r
510   Link = GetFirstNode (&UsbKeyboardDevice->NsKeyList);\r
511   while (!IsNull (&UsbKeyboardDevice->NsKeyList, Link)) {\r
512     UsbNsKey = USB_NS_KEY_FORM_FROM_LINK (Link);\r
513 \r
514     if (UsbNsKey->NsKey[0].Key == KeyDescriptor->Key) {\r
515       return UsbNsKey;\r
516     }\r
517 \r
518     Link = GetNextNode (&UsbKeyboardDevice->NsKeyList, Link);\r
519   }\r
520 \r
521   return NULL;\r
522 }\r
523 \r
524 EFI_KEY_DESCRIPTOR *\r
525 FindPhysicalKey (\r
526   IN USB_NS_KEY          *UsbNsKey,\r
527   IN EFI_KEY_DESCRIPTOR  *KeyDescriptor\r
528   )\r
529 /*++\r
530 \r
531   Routine Description:\r
532     Find physical key definition for a given Key stroke.\r
533 \r
534   Arguments:\r
535     UsbNsKey        -  The Non-Spacing key information.\r
536     KeyDescriptor   -  The key stroke.\r
537 \r
538   Returns:\r
539     The physical key definition.\r
540 \r
541 --*/\r
542 {\r
543   UINTN               Index;\r
544   EFI_KEY_DESCRIPTOR  *PhysicalKey;\r
545 \r
546   PhysicalKey = &UsbNsKey->NsKey[1];\r
547   for (Index = 0; Index < UsbNsKey->KeyCount; Index++) {\r
548     if (KeyDescriptor->Key == PhysicalKey->Key) {\r
549       return PhysicalKey;\r
550     }\r
551 \r
552     PhysicalKey++;\r
553   }\r
554 \r
555   //\r
556   // No children definition matched, return original key\r
557   //\r
558   return KeyDescriptor;\r
559 }\r
560 \r
561 VOID\r
562 EFIAPI\r
563 SetKeyboardLayoutEvent (\r
564   EFI_EVENT                  Event,\r
565   VOID                       *Context\r
566   )\r
567 /*++\r
568 \r
569   Routine Description:\r
570     The notification function for SET_KEYBOARD_LAYOUT_EVENT.\r
571 \r
572   Arguments:\r
573 \r
574   Returns:\r
575 \r
576 --*/\r
577 {\r
578   USB_KB_DEV                *UsbKeyboardDevice;\r
579   EFI_HII_KEYBOARD_LAYOUT   *KeyboardLayout;\r
580   EFI_KEY_DESCRIPTOR        TempKey;\r
581   EFI_KEY_DESCRIPTOR        *KeyDescriptor;\r
582   EFI_KEY_DESCRIPTOR        *TableEntry;\r
583   EFI_KEY_DESCRIPTOR        *NsKey;\r
584   USB_NS_KEY                *UsbNsKey;\r
585   UINTN                     Index;\r
586   UINTN                     Index2;\r
587   UINTN                     KeyCount;\r
588   UINT8                     ScanCode;\r
589 \r
590   UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
591 \r
592   //\r
593   // Try to get current Keyboard Layout from HII database\r
594   //\r
595   KeyboardLayout = GetCurrentKeyboardLayout ();\r
596   if (KeyboardLayout == NULL) {\r
597     return;\r
598   }\r
599 \r
600   //\r
601   // Allocate resource for KeyConvertionTable\r
602   //\r
603   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
604   UsbKeyboardDevice->KeyConvertionTable = AllocateZeroPool ((USB_KEYCODE_MAX_MAKE + 8) * sizeof (EFI_KEY_DESCRIPTOR));\r
605   ASSERT (UsbKeyboardDevice->KeyConvertionTable != NULL);\r
606 \r
607   KeyDescriptor = (EFI_KEY_DESCRIPTOR *) (((UINT8 *) KeyboardLayout) + sizeof (EFI_HII_KEYBOARD_LAYOUT));\r
608   for (Index = 0; Index < KeyboardLayout->DescriptorCount; Index++) {\r
609     //\r
610     // Copy from HII keyboard layout package binary for alignment\r
611     //\r
612     CopyMem (&TempKey, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));\r
613 \r
614     //\r
615     // Fill the key into KeyConvertionTable (which use USB Scan Code as index)\r
616     //\r
617     ScanCode = UsbScanCodeConvertionTable [(UINT8) (TempKey.Key)];\r
618     TableEntry = GetKeyDescriptor (UsbKeyboardDevice, ScanCode);\r
619     CopyMem (TableEntry, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));\r
620 \r
621     if (TempKey.Modifier == EFI_NS_KEY_MODIFIER) {\r
622       //\r
623       // Non-spacing key\r
624       //\r
625       UsbNsKey = AllocatePool (sizeof (USB_NS_KEY));\r
626       ASSERT (UsbNsKey != NULL);\r
627 \r
628       //\r
629       // Search for sequential children physical key definitions\r
630       //\r
631       KeyCount = 0;\r
632       NsKey = KeyDescriptor + 1;\r
633       for (Index2 = Index + 1; Index2 < KeyboardLayout->DescriptorCount; Index2++) {\r
634         CopyMem (&TempKey, NsKey, sizeof (EFI_KEY_DESCRIPTOR));\r
635         if (TempKey.Modifier & EFI_NS_KEY_DEPENDENCY_MODIFIER) {\r
636           KeyCount++;\r
637         } else {\r
638           break;\r
639         }\r
640         NsKey++;\r
641       }\r
642 \r
643       UsbNsKey->Signature = USB_NS_KEY_SIGNATURE;\r
644       UsbNsKey->KeyCount = KeyCount;\r
645       UsbNsKey->NsKey = AllocateCopyPool (\r
646                           (KeyCount + 1) * sizeof (EFI_KEY_DESCRIPTOR),\r
647                           KeyDescriptor\r
648                           );\r
649       InsertTailList (&UsbKeyboardDevice->NsKeyList, &UsbNsKey->Link);\r
650 \r
651       //\r
652       // Skip over the child physical keys\r
653       //\r
654       Index += KeyCount;\r
655       KeyDescriptor += KeyCount;\r
656     }\r
657 \r
658     KeyDescriptor++;\r
659   }\r
660 \r
661   //\r
662   // There are two EfiKeyEnter, duplicate its Key Descriptor\r
663   //\r
664   TableEntry = GetKeyDescriptor (UsbKeyboardDevice, 0x58);\r
665   KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, 0x28);\r
666   CopyMem (TableEntry, KeyDescriptor, sizeof (EFI_KEY_DESCRIPTOR));\r
667 \r
668   gBS->FreePool (KeyboardLayout);\r
669 }\r
670 \r
671 VOID\r
672 ReleaseKeyboardLayoutResources (\r
673   IN USB_KB_DEV              *UsbKeyboardDevice\r
674   )\r
675 /*++\r
676 \r
677   Routine Description:\r
678     Destroy resources for Keyboard layout.\r
679 \r
680   Arguments:\r
681     UsbKeyboardDevice  -  The USB_KB_DEV instance.\r
682 \r
683   Returns:\r
684     None.\r
685 \r
686 --*/\r
687 {\r
688   USB_NS_KEY      *UsbNsKey;\r
689   LIST_ENTRY      *Link;\r
690 \r
691   SafeFreePool (UsbKeyboardDevice->KeyConvertionTable);\r
692   UsbKeyboardDevice->KeyConvertionTable = NULL;\r
693 \r
694   while (!IsListEmpty (&UsbKeyboardDevice->NsKeyList)) {\r
695     Link = GetFirstNode (&UsbKeyboardDevice->NsKeyList);\r
696     UsbNsKey = USB_NS_KEY_FORM_FROM_LINK (Link);\r
697     RemoveEntryList (&UsbNsKey->Link);\r
698 \r
699     gBS->FreePool (UsbNsKey->NsKey);\r
700     gBS->FreePool (UsbNsKey);\r
701   }\r
702 }\r
703 \r
704 EFI_STATUS\r
705 InitKeyboardLayout (\r
706   IN USB_KB_DEV   *UsbKeyboardDevice\r
707   )\r
708 /*++\r
709 \r
710   Routine Description:\r
711     Initialize USB Keyboard layout.\r
712 \r
713   Arguments:\r
714     UsbKeyboardDevice    The USB_KB_DEV instance.\r
715 \r
716   Returns:\r
717     EFI_SUCCESS  - Success\r
718     Other        - Keyboard layout initial failed.\r
719 --*/\r
720 {\r
721   EFI_HII_KEYBOARD_LAYOUT   *KeyboardLayout;\r
722   EFI_STATUS                Status;\r
723 \r
724   UsbKeyboardDevice->KeyConvertionTable = AllocateZeroPool ((USB_KEYCODE_MAX_MAKE + 8) * sizeof (EFI_KEY_DESCRIPTOR));\r
725   ASSERT (UsbKeyboardDevice->KeyConvertionTable != NULL);\r
726 \r
727   InitializeListHead (&UsbKeyboardDevice->NsKeyList);\r
728   UsbKeyboardDevice->CurrentNsKey = NULL;\r
729   UsbKeyboardDevice->KeyboardLayoutEvent = NULL;\r
730 \r
731   //\r
732   // Register SET_KEYBOARD_LAYOUT_EVENT notification\r
733   //\r
734   Status = gBS->CreateEventEx (\r
735                   EFI_EVENT_NOTIFY_SIGNAL,\r
736                   TPL_NOTIFY,\r
737                   SetKeyboardLayoutEvent,\r
738                   UsbKeyboardDevice,\r
739                   &mKeyboardLayoutEventGuid,\r
740                   &UsbKeyboardDevice->KeyboardLayoutEvent\r
741                   );\r
742   if (EFI_ERROR (Status)) {\r
743     return Status;\r
744   }\r
745 \r
746   //\r
747   // Try to get current keyboard layout from HII database\r
748   //\r
749   KeyboardLayout = GetCurrentKeyboardLayout ();\r
750   if (KeyboardLayout != NULL) {\r
751     //\r
752     // Force to initialize the keyboard layout\r
753     //\r
754     gBS->SignalEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
755   } else {\r
756     if (FeaturePcdGet (PcdDisableDefaultKeyboardLayoutInUsbKbDriver)) {\r
757       return EFI_NOT_READY;\r
758     } else {\r
759 \r
760       //\r
761       // Fail to get keyboard layout from HII database,\r
762       // use default keyboard layout\r
763       //\r
764       LoadDefaultKeyboardLayout (UsbKeyboardDevice);\r
765     }\r
766   }\r
767   \r
768   return EFI_SUCCESS;\r
769 }\r
770 \r
771 \r
772 /**\r
773   Initialize USB Keyboard device and all private data structures.\r
774 \r
775   UsbKeyboardDevice    The USB_KB_DEV instance.\r
776 \r
777   @retval EFI_SUCCESS        Success\r
778   @retval EFI_DEVICE_ERROR   Hardware Error\r
779 \r
780 **/\r
781 EFI_STATUS\r
782 InitUSBKeyboard (\r
783   IN USB_KB_DEV   *UsbKeyboardDevice\r
784   )\r
785 {\r
786   UINT8               ConfigValue;\r
787   UINT8               Protocol;\r
788   UINT8               ReportId;\r
789   UINT8               Duration;\r
790   EFI_STATUS          Status;\r
791   UINT32              TransferResult;\r
792 \r
793   KbdReportStatusCode (\r
794     UsbKeyboardDevice->DevicePath,\r
795     EFI_PROGRESS_CODE,\r
796     PcdGet32 (PcdStatusCodeValueKeyboardSelfTest)\r
797     );\r
798 \r
799   InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));\r
800 \r
801   //\r
802   // default configurations\r
803   //\r
804   ConfigValue = 0x01;\r
805 \r
806   //\r
807   // Uses default configuration to configure the USB Keyboard device.\r
808   //\r
809   Status = UsbSetConfiguration (\r
810             UsbKeyboardDevice->UsbIo,\r
811             (UINT16) ConfigValue,\r
812             &TransferResult\r
813             );\r
814   if (EFI_ERROR (Status)) {\r
815     //\r
816     // If configuration could not be set here, it means\r
817     // the keyboard interface has some errors and could\r
818     // not be initialized\r
819     //\r
820     KbdReportStatusCode (\r
821       UsbKeyboardDevice->DevicePath,\r
822       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
823       PcdGet32 (PcdStatusCodeValueKeyboardInterfaceError)\r
824       );\r
825 \r
826     return EFI_DEVICE_ERROR;\r
827   }\r
828 \r
829   UsbGetProtocolRequest (\r
830     UsbKeyboardDevice->UsbIo,\r
831     UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,\r
832     &Protocol\r
833     );\r
834   //\r
835   // Sets boot protocol for the USB Keyboard.\r
836   // This driver only supports boot protocol.\r
837   // !!BugBug: How about the device that does not support boot protocol?\r
838   //\r
839   if (Protocol != BOOT_PROTOCOL) {\r
840     UsbSetProtocolRequest (\r
841       UsbKeyboardDevice->UsbIo,\r
842       UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,\r
843       BOOT_PROTOCOL\r
844       );\r
845   }\r
846   //\r
847   // the duration is indefinite, so the endpoint will inhibit reporting forever,\r
848   // and only reporting when a change is detected in the report data.\r
849   //\r
850 \r
851   //\r
852   // idle value for all report ID\r
853   //\r
854   ReportId = 0;\r
855   //\r
856   // idle forever until there is a key pressed and released.\r
857   //\r
858   Duration = 0;\r
859   UsbSetIdleRequest (\r
860     UsbKeyboardDevice->UsbIo,\r
861     UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,\r
862     ReportId,\r
863     Duration\r
864     );\r
865 \r
866   UsbKeyboardDevice->CtrlOn     = 0;\r
867   UsbKeyboardDevice->AltOn      = 0;\r
868   UsbKeyboardDevice->ShiftOn    = 0;\r
869   UsbKeyboardDevice->NumLockOn  = 0;\r
870   UsbKeyboardDevice->CapsOn     = 0;\r
871   UsbKeyboardDevice->ScrollOn   = 0;\r
872   \r
873   UsbKeyboardDevice->LeftCtrlOn   = 0;\r
874   UsbKeyboardDevice->LeftAltOn    = 0;\r
875   UsbKeyboardDevice->LeftShiftOn  = 0;\r
876   UsbKeyboardDevice->LeftLogoOn   = 0;\r
877   UsbKeyboardDevice->RightCtrlOn  = 0;\r
878   UsbKeyboardDevice->RightAltOn   = 0;\r
879   UsbKeyboardDevice->RightShiftOn = 0;\r
880   UsbKeyboardDevice->RightLogoOn  = 0;\r
881   UsbKeyboardDevice->MenuKeyOn    = 0;\r
882   UsbKeyboardDevice->SysReqOn     = 0;\r
883 \r
884   UsbKeyboardDevice->AltGrOn      = 0;\r
885 \r
886   UsbKeyboardDevice->CurrentNsKey = NULL;\r
887 \r
888   //\r
889   // Sync the initial state of lights\r
890   //\r
891   SetKeyLED (UsbKeyboardDevice);\r
892 \r
893   ZeroMem (UsbKeyboardDevice->LastKeyCodeArray, sizeof (UINT8) * 8);\r
894 \r
895   //\r
896   // Set a timer for repeat keys' generation.\r
897   //\r
898   if (UsbKeyboardDevice->RepeatTimer) {\r
899     gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);\r
900     UsbKeyboardDevice->RepeatTimer = 0;\r
901   }\r
902 \r
903   Status = gBS->CreateEvent (\r
904                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
905                   TPL_NOTIFY,\r
906                   USBKeyboardRepeatHandler,\r
907                   UsbKeyboardDevice,\r
908                   &UsbKeyboardDevice->RepeatTimer\r
909                   );\r
910 \r
911   if (UsbKeyboardDevice->DelayedRecoveryEvent) {\r
912     gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);\r
913     UsbKeyboardDevice->DelayedRecoveryEvent = 0;\r
914   }\r
915 \r
916   Status = gBS->CreateEvent (\r
917                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
918                   TPL_NOTIFY,\r
919                   USBKeyboardRecoveryHandler,\r
920                   UsbKeyboardDevice,\r
921                   &UsbKeyboardDevice->DelayedRecoveryEvent\r
922                   );\r
923 \r
924   return EFI_SUCCESS;\r
925 }\r
926 \r
927 \r
928 /**\r
929   Handler function for USB Keyboard's asynchronous interrupt transfer.\r
930 \r
931   Data       A pointer to a buffer that is filled with key data which is\r
932   retrieved via asynchronous interrupt transfer.\r
933   DataLength Indicates the size of the data buffer.\r
934   Context    Pointing to USB_KB_DEV instance.\r
935   Result     Indicates the result of the asynchronous interrupt transfer.\r
936 \r
937   @retval EFI_SUCCESS        Success\r
938   @retval EFI_DEVICE_ERROR   Hardware Error\r
939 \r
940 **/\r
941 EFI_STATUS\r
942 EFIAPI\r
943 KeyboardHandler (\r
944   IN  VOID          *Data,\r
945   IN  UINTN         DataLength,\r
946   IN  VOID          *Context,\r
947   IN  UINT32        Result\r
948   )\r
949 {\r
950   USB_KB_DEV          *UsbKeyboardDevice;\r
951   EFI_USB_IO_PROTOCOL *UsbIo;\r
952   UINT8               *CurKeyCodeBuffer;\r
953   UINT8               *OldKeyCodeBuffer;\r
954   UINT8               CurModifierMap;\r
955   UINT8               OldModifierMap;\r
956   UINT8               Index;\r
957   UINT8               Index2;\r
958   BOOLEAN             Down;\r
959   BOOLEAN             KeyRelease;\r
960   BOOLEAN             KeyPress;\r
961   UINT8               SavedTail;\r
962   USB_KEY             UsbKey;\r
963   UINT8               NewRepeatKey;\r
964   UINT32              UsbStatus;\r
965   EFI_KEY_DESCRIPTOR  *KeyDescriptor;\r
966 \r
967   ASSERT (Context);\r
968 \r
969   NewRepeatKey      = 0;\r
970   UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
971   UsbIo             = UsbKeyboardDevice->UsbIo;\r
972 \r
973   //\r
974   // Analyzes the Result and performs corresponding action.\r
975   //\r
976   if (Result != EFI_USB_NOERROR) {\r
977     //\r
978     // Some errors happen during the process\r
979     //\r
980     KbdReportStatusCode (\r
981       UsbKeyboardDevice->DevicePath,\r
982       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
983       PcdGet32 (PcdStatusCodeValueKeyboardInputError)\r
984       );\r
985 \r
986     //\r
987     // stop the repeat key generation if any\r
988     //\r
989     UsbKeyboardDevice->RepeatKey = 0;\r
990 \r
991     gBS->SetTimer (\r
992           UsbKeyboardDevice->RepeatTimer,\r
993           TimerCancel,\r
994           USBKBD_REPEAT_RATE\r
995           );\r
996 \r
997     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {\r
998       UsbClearEndpointHalt (\r
999         UsbIo,\r
1000         UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,\r
1001         &UsbStatus\r
1002         );\r
1003     }\r
1004 \r
1005     //\r
1006     // Delete & Submit this interrupt again\r
1007     //\r
1008 \r
1009     UsbIo->UsbAsyncInterruptTransfer (\r
1010                       UsbIo,\r
1011                       UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,\r
1012                       FALSE,\r
1013                       0,\r
1014                       0,\r
1015                       NULL,\r
1016                       NULL\r
1017                       );\r
1018 \r
1019     gBS->SetTimer (\r
1020           UsbKeyboardDevice->DelayedRecoveryEvent,\r
1021           TimerRelative,\r
1022           EFI_USB_INTERRUPT_DELAY\r
1023           );\r
1024 \r
1025     return EFI_DEVICE_ERROR;\r
1026   }\r
1027 \r
1028   if (DataLength == 0 || Data == NULL) {\r
1029     return EFI_SUCCESS;\r
1030   }\r
1031 \r
1032   CurKeyCodeBuffer  = (UINT8 *) Data;\r
1033   OldKeyCodeBuffer  = UsbKeyboardDevice->LastKeyCodeArray;\r
1034 \r
1035   //\r
1036   // checks for new key stroke.\r
1037   // if no new key got, return immediately.\r
1038   //\r
1039   for (Index = 0; Index < 8; Index++) {\r
1040     if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) {\r
1041       break;\r
1042     }\r
1043   }\r
1044 \r
1045   if (Index == 8) {\r
1046     return EFI_SUCCESS;\r
1047   }\r
1048 \r
1049   //\r
1050   // Parse the modifier key\r
1051   //\r
1052   CurModifierMap  = CurKeyCodeBuffer[0];\r
1053   OldModifierMap  = OldKeyCodeBuffer[0];\r
1054 \r
1055   //\r
1056   // handle modifier key's pressing or releasing situation.\r
1057   //\r
1058   for (Index = 0; Index < 8; Index++) {\r
1059 \r
1060     if ((CurModifierMap & KB_Mod[Index].Mask) != (OldModifierMap & KB_Mod[Index].Mask)) {\r
1061       //\r
1062       // if current modifier key is up, then\r
1063       // CurModifierMap & KB_Mod[Index].Mask = 0;\r
1064       // otherwize it is a non-zero value.\r
1065       // Inserts the pressed modifier key into key buffer.\r
1066       //\r
1067       Down = (UINT8) (CurModifierMap & KB_Mod[Index].Mask);\r
1068       InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), KB_Mod[Index].Key, Down);\r
1069     }\r
1070   }\r
1071 \r
1072   //\r
1073   // handle normal key's releasing situation\r
1074   //\r
1075   KeyRelease = FALSE;\r
1076   for (Index = 2; Index < 8; Index++) {\r
1077 \r
1078     if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) {\r
1079       continue;\r
1080     }\r
1081 \r
1082     KeyRelease = TRUE;\r
1083     for (Index2 = 2; Index2 < 8; Index2++) {\r
1084 \r
1085       if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index2])) {\r
1086         continue;\r
1087       }\r
1088 \r
1089       if (OldKeyCodeBuffer[Index] == CurKeyCodeBuffer[Index2]) {\r
1090         KeyRelease = FALSE;\r
1091         break;\r
1092       }\r
1093     }\r
1094 \r
1095     if (KeyRelease) {\r
1096       InsertKeyCode (\r
1097         &(UsbKeyboardDevice->KeyboardBuffer),\r
1098         OldKeyCodeBuffer[Index],\r
1099         0\r
1100         );\r
1101       //\r
1102       // the original reapeat key is released.\r
1103       //\r
1104       if (OldKeyCodeBuffer[Index] == UsbKeyboardDevice->RepeatKey) {\r
1105         UsbKeyboardDevice->RepeatKey = 0;\r
1106       }\r
1107     }\r
1108   }\r
1109 \r
1110   //\r
1111   // original repeat key is released, cancel the repeat timer\r
1112   //\r
1113   if (UsbKeyboardDevice->RepeatKey == 0) {\r
1114     gBS->SetTimer (\r
1115           UsbKeyboardDevice->RepeatTimer,\r
1116           TimerCancel,\r
1117           USBKBD_REPEAT_RATE\r
1118           );\r
1119   }\r
1120 \r
1121   //\r
1122   // handle normal key's pressing situation\r
1123   //\r
1124   KeyPress = FALSE;\r
1125   for (Index = 2; Index < 8; Index++) {\r
1126 \r
1127     if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index])) {\r
1128       continue;\r
1129     }\r
1130 \r
1131     KeyPress = TRUE;\r
1132     for (Index2 = 2; Index2 < 8; Index2++) {\r
1133 \r
1134       if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index2])) {\r
1135         continue;\r
1136       }\r
1137 \r
1138       if (CurKeyCodeBuffer[Index] == OldKeyCodeBuffer[Index2]) {\r
1139         KeyPress = FALSE;\r
1140         break;\r
1141       }\r
1142     }\r
1143 \r
1144     if (KeyPress) {\r
1145       InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), CurKeyCodeBuffer[Index], 1);\r
1146       //\r
1147       // NumLock pressed or CapsLock pressed\r
1148       //\r
1149       KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, CurKeyCodeBuffer[Index]);\r
1150       if (KeyDescriptor->Modifier == EFI_NUM_LOCK_MODIFIER || KeyDescriptor->Modifier == EFI_CAPS_LOCK_MODIFIER) {\r
1151         UsbKeyboardDevice->RepeatKey = 0;\r
1152       } else {\r
1153         NewRepeatKey = CurKeyCodeBuffer[Index];\r
1154         //\r
1155         // do not repeat the original repeated key\r
1156         //\r
1157         UsbKeyboardDevice->RepeatKey = 0;\r
1158       }\r
1159     }\r
1160   }\r
1161 \r
1162   //\r
1163   // Update LastKeycodeArray[] buffer in the\r
1164   // Usb Keyboard Device data structure.\r
1165   //\r
1166   for (Index = 0; Index < 8; Index++) {\r
1167     UsbKeyboardDevice->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index];\r
1168   }\r
1169 \r
1170   //\r
1171   // pre-process KeyboardBuffer, pop out the ctrl,alt,del key in sequence\r
1172   // and judge whether it will invoke reset event.\r
1173   //\r
1174   SavedTail = UsbKeyboardDevice->KeyboardBuffer.bTail;\r
1175   Index     = UsbKeyboardDevice->KeyboardBuffer.bHead;\r
1176   while (Index != SavedTail) {\r
1177     RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey);\r
1178 \r
1179     KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, UsbKey.KeyCode);\r
1180 \r
1181     switch (KeyDescriptor->Modifier) {\r
1182 \r
1183     case EFI_LEFT_CONTROL_MODIFIER:\r
1184     case EFI_RIGHT_CONTROL_MODIFIER:\r
1185       if (UsbKey.Down) {\r
1186         UsbKeyboardDevice->CtrlOn = 1;\r
1187       } else {\r
1188         UsbKeyboardDevice->CtrlOn = 0;\r
1189       }\r
1190       break;\r
1191 \r
1192     case EFI_LEFT_ALT_MODIFIER:\r
1193     case EFI_RIGHT_ALT_MODIFIER:\r
1194       if (UsbKey.Down) {\r
1195         UsbKeyboardDevice->AltOn = 1;\r
1196       } else {\r
1197         UsbKeyboardDevice->AltOn = 0;\r
1198       }\r
1199       break;\r
1200 \r
1201     case EFI_ALT_GR_MODIFIER:\r
1202       if (UsbKey.Down) {\r
1203         UsbKeyboardDevice->AltGrOn = 1;\r
1204       } else {\r
1205         UsbKeyboardDevice->AltGrOn = 0;\r
1206       }\r
1207       break;\r
1208 \r
1209     //\r
1210     // Del Key Code\r
1211     //\r
1212     case EFI_DELETE_MODIFIER:\r
1213       if (UsbKey.Down) {\r
1214         if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) {\r
1215           gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1216         }\r
1217       }\r
1218       break;\r
1219 \r
1220     default:\r
1221       break;\r
1222     }\r
1223 \r
1224     //\r
1225     // insert the key back to the buffer.\r
1226     // so the key sequence will not be destroyed.\r
1227     //\r
1228     InsertKeyCode (\r
1229       &(UsbKeyboardDevice->KeyboardBuffer),\r
1230       UsbKey.KeyCode,\r
1231       UsbKey.Down\r
1232       );\r
1233     Index = UsbKeyboardDevice->KeyboardBuffer.bHead;\r
1234 \r
1235   }\r
1236   //\r
1237   // If have new key pressed, update the RepeatKey value, and set the\r
1238   // timer to repeate delay timer\r
1239   //\r
1240   if (NewRepeatKey != 0) {\r
1241     //\r
1242     // sets trigger time to "Repeat Delay Time",\r
1243     // to trigger the repeat timer when the key is hold long\r
1244     // enough time.\r
1245     //\r
1246     gBS->SetTimer (\r
1247           UsbKeyboardDevice->RepeatTimer,\r
1248           TimerRelative,\r
1249           USBKBD_REPEAT_DELAY\r
1250           );\r
1251     UsbKeyboardDevice->RepeatKey = NewRepeatKey;\r
1252   }\r
1253 \r
1254   return EFI_SUCCESS;\r
1255 }\r
1256 \r
1257 \r
1258 /**\r
1259   Retrieves a key character after parsing the raw data in keyboard buffer.\r
1260 \r
1261   UsbKeyboardDevice    The USB_KB_DEV instance.\r
1262   KeyChar              Points to the Key character after key parsing.\r
1263 \r
1264   @retval EFI_SUCCESS        Success\r
1265   @retval EFI_NOT_READY      Device is not ready\r
1266 \r
1267 **/\r
1268 EFI_STATUS\r
1269 USBParseKey (\r
1270   IN OUT  USB_KB_DEV  *UsbKeyboardDevice,\r
1271   OUT     UINT8       *KeyChar\r
1272   )\r
1273 {\r
1274   USB_KEY             UsbKey;\r
1275   EFI_KEY_DESCRIPTOR  *KeyDescriptor;\r
1276 \r
1277   *KeyChar = 0;\r
1278 \r
1279   while (!IsUSBKeyboardBufferEmpty (&UsbKeyboardDevice->KeyboardBuffer)) {\r
1280     //\r
1281     // pops one raw data off.\r
1282     //\r
1283     RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey);\r
1284 \r
1285     KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, UsbKey.KeyCode);\r
1286     if (!UsbKey.Down) {\r
1287       switch (KeyDescriptor->Modifier) {\r
1288 \r
1289       //\r
1290       // CTRL release\r
1291       //\r
1292       case EFI_LEFT_CONTROL_MODIFIER:\r
1293         UsbKeyboardDevice->LeftCtrlOn = 0;\r
1294         UsbKeyboardDevice->CtrlOn = 0;\r
1295         break;\r
1296       case EFI_RIGHT_CONTROL_MODIFIER:\r
1297         UsbKeyboardDevice->RightCtrlOn = 0;\r
1298         UsbKeyboardDevice->CtrlOn = 0;\r
1299         break;\r
1300 \r
1301       //\r
1302       // Shift release\r
1303       //\r
1304       case EFI_LEFT_SHIFT_MODIFIER:\r
1305         UsbKeyboardDevice->LeftShiftOn = 0;\r
1306         UsbKeyboardDevice->ShiftOn = 0;\r
1307         break;\r
1308       case EFI_RIGHT_SHIFT_MODIFIER:\r
1309         UsbKeyboardDevice->RightShiftOn = 0;\r
1310         UsbKeyboardDevice->ShiftOn = 0;\r
1311         break;\r
1312 \r
1313       //\r
1314       // Alt release\r
1315       //\r
1316       case EFI_LEFT_ALT_MODIFIER:\r
1317         UsbKeyboardDevice->LeftAltOn = 0;\r
1318         UsbKeyboardDevice->AltOn = 0;\r
1319         break;\r
1320       case EFI_RIGHT_ALT_MODIFIER:\r
1321         UsbKeyboardDevice->RightAltOn = 0;\r
1322         UsbKeyboardDevice->AltOn = 0;\r
1323         break;\r
1324 \r
1325       //\r
1326       // Left Logo release\r
1327       //\r
1328       case EFI_LEFT_LOGO_MODIFIER:\r
1329         UsbKeyboardDevice->LeftLogoOn = 0;\r
1330         break;\r
1331 \r
1332       //\r
1333       // Right Logo release\r
1334       //\r
1335       case EFI_RIGHT_LOGO_MODIFIER:\r
1336         UsbKeyboardDevice->RightLogoOn = 0;\r
1337         break;\r
1338 \r
1339       //\r
1340       // Menu key release\r
1341       //\r
1342       case EFI_MENU_MODIFIER:\r
1343         UsbKeyboardDevice->MenuKeyOn = 0;\r
1344         break;\r
1345 \r
1346       //\r
1347       // SysReq release\r
1348       //\r
1349       case EFI_PRINT_MODIFIER:\r
1350       case EFI_SYS_REQUEST_MODIFIER:\r
1351         UsbKeyboardDevice->SysReqOn = 0;\r
1352         break;\r
1353 \r
1354       //\r
1355       // AltGr release\r
1356       //\r
1357       case EFI_ALT_GR_MODIFIER:\r
1358         UsbKeyboardDevice->AltGrOn = 0;\r
1359         break;\r
1360 \r
1361       default:\r
1362         break;\r
1363       }\r
1364 \r
1365       continue;\r
1366     }\r
1367 \r
1368     //\r
1369     // Analyzes key pressing situation\r
1370     //\r
1371     switch (KeyDescriptor->Modifier) {\r
1372 \r
1373     //\r
1374     // CTRL press\r
1375     //\r
1376     case EFI_LEFT_CONTROL_MODIFIER:\r
1377       UsbKeyboardDevice->LeftCtrlOn = 1;\r
1378       UsbKeyboardDevice->CtrlOn = 1;\r
1379       continue;\r
1380       break;\r
1381     case EFI_RIGHT_CONTROL_MODIFIER:\r
1382       UsbKeyboardDevice->RightCtrlOn = 1;\r
1383       UsbKeyboardDevice->CtrlOn = 1;\r
1384       continue;\r
1385       break;\r
1386 \r
1387     //\r
1388     // Shift press\r
1389     //\r
1390     case EFI_LEFT_SHIFT_MODIFIER:\r
1391       UsbKeyboardDevice->LeftShiftOn = 1;\r
1392       UsbKeyboardDevice->ShiftOn = 1;\r
1393       continue;\r
1394       break;\r
1395     case EFI_RIGHT_SHIFT_MODIFIER:\r
1396       UsbKeyboardDevice->RightShiftOn = 1;\r
1397       UsbKeyboardDevice->ShiftOn = 1;\r
1398       continue;\r
1399       break;\r
1400 \r
1401     //\r
1402     // Alt press\r
1403     //\r
1404     case EFI_LEFT_ALT_MODIFIER:\r
1405       UsbKeyboardDevice->LeftAltOn = 1;\r
1406       UsbKeyboardDevice->AltOn = 1;\r
1407       continue;\r
1408       break;\r
1409     case EFI_RIGHT_ALT_MODIFIER:\r
1410       UsbKeyboardDevice->RightAltOn = 1;\r
1411       UsbKeyboardDevice->AltOn = 1;\r
1412       continue;\r
1413       break;\r
1414 \r
1415     //\r
1416     // Left Logo press\r
1417     //\r
1418     case EFI_LEFT_LOGO_MODIFIER:\r
1419       UsbKeyboardDevice->LeftLogoOn = 1;\r
1420       break;\r
1421 \r
1422     //\r
1423     // Right Logo press\r
1424     //\r
1425     case EFI_RIGHT_LOGO_MODIFIER:\r
1426       UsbKeyboardDevice->RightLogoOn = 1;\r
1427       break;\r
1428 \r
1429     //\r
1430     // Menu key press\r
1431     //\r
1432     case EFI_MENU_MODIFIER:\r
1433       UsbKeyboardDevice->MenuKeyOn = 1;\r
1434       break;\r
1435 \r
1436     //\r
1437     // SysReq press\r
1438     //\r
1439     case EFI_PRINT_MODIFIER:\r
1440     case EFI_SYS_REQUEST_MODIFIER:\r
1441       UsbKeyboardDevice->SysReqOn = 1;\r
1442       continue;\r
1443       break;\r
1444 \r
1445     //\r
1446     // AltGr press\r
1447     //\r
1448     case EFI_ALT_GR_MODIFIER:\r
1449       UsbKeyboardDevice->AltGrOn = 1;\r
1450       break;\r
1451 \r
1452     case EFI_NUM_LOCK_MODIFIER:\r
1453       UsbKeyboardDevice->NumLockOn ^= 1;\r
1454       //\r
1455       // Turn on the NumLock light on KB\r
1456       //\r
1457       SetKeyLED (UsbKeyboardDevice);\r
1458       continue;\r
1459       break;\r
1460 \r
1461     case EFI_CAPS_LOCK_MODIFIER:\r
1462       UsbKeyboardDevice->CapsOn ^= 1;\r
1463       //\r
1464       // Turn on the CapsLock light on KB\r
1465       //\r
1466       SetKeyLED (UsbKeyboardDevice);\r
1467       continue;\r
1468       break;\r
1469 \r
1470     case EFI_SCROLL_LOCK_MODIFIER:\r
1471       UsbKeyboardDevice->ScrollOn ^= 1;\r
1472       //\r
1473       // Turn on the ScrollLock light on KB\r
1474       //\r
1475       SetKeyLED (UsbKeyboardDevice);\r
1476       continue;\r
1477       break;\r
1478 \r
1479     //\r
1480     // F11,F12,PrintScreen,Pause/Break\r
1481     // could not be retrieved via SimpleTxtInEx protocol\r
1482     //\r
1483     case EFI_FUNCTION_KEY_ELEVEN_MODIFIER:\r
1484     case EFI_FUNCTION_KEY_TWELVE_MODIFIER:\r
1485     case EFI_PAUSE_MODIFIER:\r
1486     case EFI_BREAK_MODIFIER:\r
1487       //\r
1488       // fall through\r
1489       //\r
1490       continue;\r
1491       break;\r
1492 \r
1493     default:\r
1494       break;\r
1495     }\r
1496 \r
1497     //\r
1498     // When encountered Del Key...\r
1499     //\r
1500     if (KeyDescriptor->Modifier == EFI_DELETE_MODIFIER) {\r
1501       if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) {\r
1502         gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1503       }\r
1504     }\r
1505 \r
1506     *KeyChar = UsbKey.KeyCode;\r
1507     return EFI_SUCCESS;\r
1508   }\r
1509 \r
1510   return EFI_NOT_READY;\r
1511 }\r
1512 \r
1513 \r
1514 \r
1515 /**\r
1516   Converts USB Keyboard code to EFI Scan Code.\r
1517 \r
1518   UsbKeyboardDevice    The USB_KB_DEV instance.\r
1519   KeyChar              Indicates the key code that will be interpreted.\r
1520   Key                  A pointer to a buffer that is filled in with\r
1521   the keystroke information for the key that\r
1522   was pressed.\r
1523 \r
1524   @retval EFI_NOT_READY      Device is not ready\r
1525   @retval EFI_SUCCESS        Success\r
1526 \r
1527 **/\r
1528 EFI_STATUS\r
1529 USBKeyCodeToEFIScanCode (\r
1530   IN  USB_KB_DEV      *UsbKeyboardDevice,\r
1531   IN  UINT8           KeyChar,\r
1532   OUT EFI_INPUT_KEY   *Key\r
1533   )\r
1534 {\r
1535   UINT8               Index;\r
1536   EFI_KEY_DESCRIPTOR  *KeyDescriptor;\r
1537 \r
1538   if (!USBKBD_VALID_KEYCODE (KeyChar)) {\r
1539     return EFI_NOT_READY;\r
1540   }\r
1541 \r
1542   //\r
1543   // valid USB Key Code starts from 4\r
1544   //\r
1545   Index = (UINT8) (KeyChar - 4);\r
1546 \r
1547   if (Index >= USB_KEYCODE_MAX_MAKE) {\r
1548     return EFI_NOT_READY;\r
1549   }\r
1550 \r
1551   KeyDescriptor = GetKeyDescriptor (UsbKeyboardDevice, KeyChar);\r
1552 \r
1553   //\r
1554   // Check for Non-spacing key\r
1555   //\r
1556   if (KeyDescriptor->Modifier == EFI_NS_KEY_MODIFIER) {\r
1557     UsbKeyboardDevice->CurrentNsKey = FindUsbNsKey (UsbKeyboardDevice, KeyDescriptor);\r
1558     return EFI_NOT_READY;\r
1559   }\r
1560 \r
1561   //\r
1562   // Check whether this keystroke follows a Non-spacing key\r
1563   //\r
1564   if (UsbKeyboardDevice->CurrentNsKey != NULL) {\r
1565     KeyDescriptor = FindPhysicalKey (UsbKeyboardDevice->CurrentNsKey, KeyDescriptor);\r
1566     UsbKeyboardDevice->CurrentNsKey = NULL;\r
1567   }\r
1568 \r
1569   Key->ScanCode = EfiScanCodeConvertionTable[KeyDescriptor->Modifier];\r
1570   Key->UnicodeChar = KeyDescriptor->Unicode;\r
1571 \r
1572   if (KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_STANDARD_SHIFT) {\r
1573     if (UsbKeyboardDevice->ShiftOn) {\r
1574       Key->UnicodeChar = KeyDescriptor->ShiftedUnicode;\r
1575 \r
1576       //\r
1577       // Need not return associated shift state if a class of printable characters that\r
1578       // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'\r
1579       //\r
1580       if (KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_CAPS_LOCK) {\r
1581         UsbKeyboardDevice->LeftShiftOn = 0;\r
1582         UsbKeyboardDevice->RightShiftOn = 0;\r
1583       }\r
1584 \r
1585       if (UsbKeyboardDevice->AltGrOn) {\r
1586         Key->UnicodeChar = KeyDescriptor->ShiftedAltGrUnicode;\r
1587       }\r
1588     } else {\r
1589       //\r
1590       // Shift off\r
1591       //\r
1592       Key->UnicodeChar = KeyDescriptor->Unicode;\r
1593 \r
1594       if (UsbKeyboardDevice->AltGrOn) {\r
1595         Key->UnicodeChar = KeyDescriptor->AltGrUnicode;\r
1596       }\r
1597     }\r
1598   }\r
1599 \r
1600   if (KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_CAPS_LOCK) {\r
1601     if (UsbKeyboardDevice->CapsOn) {\r
1602 \r
1603       if (Key->UnicodeChar == KeyDescriptor->Unicode) {\r
1604 \r
1605         Key->UnicodeChar = KeyDescriptor->ShiftedUnicode;\r
1606 \r
1607       } else if (Key->UnicodeChar == KeyDescriptor->ShiftedUnicode) {\r
1608 \r
1609         Key->UnicodeChar = KeyDescriptor->Unicode;\r
1610 \r
1611       }\r
1612     }\r
1613   }\r
1614 \r
1615   //\r
1616   // Translate the CTRL-Alpha characters to their corresponding control value  (ctrl-a = 0x0001 through ctrl-Z = 0x001A)\r
1617   //\r
1618   if (UsbKeyboardDevice->CtrlOn) {\r
1619     if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') {\r
1620       Key->UnicodeChar = (UINT8) (Key->UnicodeChar - 'a' + 1);\r
1621     } else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') {\r
1622       Key->UnicodeChar = (UINT8) (Key->UnicodeChar - 'A' + 1);\r
1623     }\r
1624   }\r
1625 \r
1626   if (KeyDescriptor->AffectedAttribute & EFI_AFFECTED_BY_NUM_LOCK) {\r
1627 \r
1628     if (UsbKeyboardDevice->NumLockOn && !UsbKeyboardDevice->ShiftOn) {\r
1629 \r
1630       Key->ScanCode = SCAN_NULL;\r
1631 \r
1632     } else {\r
1633       Key->UnicodeChar = 0x00;\r
1634     }\r
1635   }\r
1636 \r
1637   //\r
1638   // Translate Unicode 0x1B (ESC) to EFI Scan Code\r
1639   //\r
1640   if (Key->UnicodeChar == 0x1B && Key->ScanCode == SCAN_NULL) {\r
1641     Key->ScanCode = SCAN_ESC;\r
1642     Key->UnicodeChar = 0x00;\r
1643   }\r
1644 \r
1645   if (Key->UnicodeChar == 0 && Key->ScanCode == SCAN_NULL) {\r
1646     return EFI_NOT_READY;\r
1647   }\r
1648 \r
1649 \r
1650   //\r
1651   // Save Shift/Toggle state\r
1652   //\r
1653   if (UsbKeyboardDevice->LeftCtrlOn == 1) {\r
1654     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;\r
1655   }\r
1656   if (UsbKeyboardDevice->RightCtrlOn == 1) {\r
1657     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;\r
1658   }\r
1659   if (UsbKeyboardDevice->LeftAltOn == 1) {\r
1660     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;\r
1661   }\r
1662   if (UsbKeyboardDevice->RightAltOn == 1) {\r
1663     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_ALT_PRESSED;\r
1664   }\r
1665   if (UsbKeyboardDevice->LeftShiftOn == 1) {\r
1666     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;\r
1667   }\r
1668   if (UsbKeyboardDevice->RightShiftOn == 1) {\r
1669     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;\r
1670   }\r
1671   if (UsbKeyboardDevice->LeftLogoOn == 1) {\r
1672     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;\r
1673   }\r
1674   if (UsbKeyboardDevice->RightLogoOn == 1) {\r
1675     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;\r
1676   }\r
1677   if (UsbKeyboardDevice->MenuKeyOn == 1) {\r
1678     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_MENU_KEY_PRESSED;\r
1679   }\r
1680   if (UsbKeyboardDevice->SysReqOn == 1) {\r
1681     UsbKeyboardDevice->KeyState.KeyShiftState |= EFI_SYS_REQ_PRESSED;\r
1682   }\r
1683 \r
1684   if (UsbKeyboardDevice->ScrollOn == 1) {\r
1685     UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
1686   }\r
1687   if (UsbKeyboardDevice->NumLockOn == 1) {\r
1688     UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
1689   }\r
1690   if (UsbKeyboardDevice->CapsOn == 1) {\r
1691     UsbKeyboardDevice->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
1692   }\r
1693 \r
1694   return EFI_SUCCESS;\r
1695 \r
1696 }\r
1697 \r
1698 \r
1699 \r
1700 /**\r
1701   Resets USB Keyboard Buffer.\r
1702 \r
1703   @param  KeyboardBuffer     Points to the USB Keyboard Buffer.\r
1704 \r
1705   @retval EFI_SUCCESS        Success\r
1706 \r
1707 **/\r
1708 EFI_STATUS\r
1709 InitUSBKeyBuffer (\r
1710   IN OUT  USB_KB_BUFFER   *KeyboardBuffer\r
1711   )\r
1712 {\r
1713   ZeroMem (KeyboardBuffer, sizeof (USB_KB_BUFFER));\r
1714 \r
1715   KeyboardBuffer->bHead = KeyboardBuffer->bTail;\r
1716 \r
1717   return EFI_SUCCESS;\r
1718 }\r
1719 \r
1720 \r
1721 /**\r
1722   Check whether USB Keyboard buffer is empty.\r
1723 \r
1724   @param  KeyboardBuffer     USB Keyboard Buffer.\r
1725 \r
1726 \r
1727 **/\r
1728 BOOLEAN\r
1729 IsUSBKeyboardBufferEmpty (\r
1730   IN  USB_KB_BUFFER   *KeyboardBuffer\r
1731   )\r
1732 {\r
1733   //\r
1734   // meet FIFO empty condition\r
1735   //\r
1736   return (BOOLEAN) (KeyboardBuffer->bHead == KeyboardBuffer->bTail);\r
1737 }\r
1738 \r
1739 \r
1740 \r
1741 /**\r
1742   Check whether USB Keyboard buffer is full.\r
1743 \r
1744   @param  KeyboardBuffer     USB Keyboard Buffer.\r
1745 \r
1746 \r
1747 **/\r
1748 BOOLEAN\r
1749 IsUSBKeyboardBufferFull (\r
1750   IN  USB_KB_BUFFER   *KeyboardBuffer\r
1751   )\r
1752 {\r
1753   return (BOOLEAN)(((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)) ==\r
1754                                                         KeyboardBuffer->bHead);\r
1755 }\r
1756 \r
1757 \r
1758 \r
1759 /**\r
1760   Inserts a key code into keyboard buffer.\r
1761 \r
1762   @param  KeyboardBuffer     Points to the USB Keyboard Buffer.\r
1763   @param  Key                Key code\r
1764   @param  Down               Special key\r
1765 \r
1766   @retval EFI_SUCCESS        Success\r
1767 \r
1768 **/\r
1769 EFI_STATUS\r
1770 InsertKeyCode (\r
1771   IN OUT  USB_KB_BUFFER *KeyboardBuffer,\r
1772   IN      UINT8         Key,\r
1773   IN      UINT8         Down\r
1774   )\r
1775 {\r
1776   USB_KEY UsbKey;\r
1777 \r
1778   //\r
1779   // if keyboard buffer is full, throw the\r
1780   // first key out of the keyboard buffer.\r
1781   //\r
1782   if (IsUSBKeyboardBufferFull (KeyboardBuffer)) {\r
1783     RemoveKeyCode (KeyboardBuffer, &UsbKey);\r
1784   }\r
1785 \r
1786   KeyboardBuffer->buffer[KeyboardBuffer->bTail].KeyCode = Key;\r
1787   KeyboardBuffer->buffer[KeyboardBuffer->bTail].Down    = Down;\r
1788 \r
1789   //\r
1790   // adjust the tail pointer of the FIFO keyboard buffer.\r
1791   //\r
1792   KeyboardBuffer->bTail = (UINT8) ((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1));\r
1793 \r
1794   return EFI_SUCCESS;\r
1795 }\r
1796 \r
1797 \r
1798 /**\r
1799   Pops a key code off from keyboard buffer.\r
1800 \r
1801   @param  KeyboardBuffer     Points to the USB Keyboard Buffer.\r
1802   @param  UsbKey             Points to the buffer that contains a usb key code.\r
1803 \r
1804   @retval EFI_SUCCESS        Success\r
1805   @retval EFI_DEVICE_ERROR   Hardware Error\r
1806 \r
1807 **/\r
1808 EFI_STATUS\r
1809 RemoveKeyCode (\r
1810   IN OUT  USB_KB_BUFFER *KeyboardBuffer,\r
1811   OUT     USB_KEY       *UsbKey\r
1812   )\r
1813 {\r
1814   if (IsUSBKeyboardBufferEmpty (KeyboardBuffer)) {\r
1815     return EFI_DEVICE_ERROR;\r
1816   }\r
1817 \r
1818   UsbKey->KeyCode = KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode;\r
1819   UsbKey->Down    = KeyboardBuffer->buffer[KeyboardBuffer->bHead].Down;\r
1820 \r
1821   //\r
1822   // adjust the head pointer of the FIFO keyboard buffer.\r
1823   //\r
1824   KeyboardBuffer->bHead = (UINT8) ((KeyboardBuffer->bHead + 1) % (MAX_KEY_ALLOWED + 1));\r
1825 \r
1826   return EFI_SUCCESS;\r
1827 }\r
1828 \r
1829 \r
1830 /**\r
1831   Sets USB Keyboard LED state.\r
1832 \r
1833   @param  UsbKeyboardDevice  The USB_KB_DEV instance.\r
1834 \r
1835   @retval EFI_SUCCESS        Success\r
1836 \r
1837 **/\r
1838 EFI_STATUS\r
1839 SetKeyLED (\r
1840   IN  USB_KB_DEV    *UsbKeyboardDevice\r
1841   )\r
1842 {\r
1843   LED_MAP Led;\r
1844   UINT8   ReportId;\r
1845 \r
1846   //\r
1847   // Set each field in Led map.\r
1848   //\r
1849   Led.NumLock    = (UINT8) UsbKeyboardDevice->NumLockOn;\r
1850   Led.CapsLock   = (UINT8) UsbKeyboardDevice->CapsOn;\r
1851   Led.ScrollLock = (UINT8) UsbKeyboardDevice->ScrollOn;\r
1852   Led.Resrvd     = 0;\r
1853 \r
1854   ReportId       = 0;\r
1855   //\r
1856   // call Set Report Request to lighten the LED.\r
1857   //\r
1858   UsbSetReportRequest (\r
1859     UsbKeyboardDevice->UsbIo,\r
1860     UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber,\r
1861     ReportId,\r
1862     HID_OUTPUT_REPORT,\r
1863     1,\r
1864     (UINT8 *) &Led\r
1865     );\r
1866 \r
1867   return EFI_SUCCESS;\r
1868 }\r
1869 \r
1870 \r
1871 /**\r
1872   Timer handler for Repeat Key timer.\r
1873 \r
1874   @param  Event              The Repeat Key event.\r
1875   @param  Context            Points to the USB_KB_DEV instance.\r
1876 \r
1877 \r
1878 **/\r
1879 VOID\r
1880 EFIAPI\r
1881 USBKeyboardRepeatHandler (\r
1882   IN    EFI_EVENT    Event,\r
1883   IN    VOID         *Context\r
1884   )\r
1885 {\r
1886   USB_KB_DEV  *UsbKeyboardDevice;\r
1887 \r
1888   UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
1889 \r
1890   //\r
1891   // Do nothing when there is no repeat key.\r
1892   //\r
1893   if (UsbKeyboardDevice->RepeatKey != 0) {\r
1894     //\r
1895     // Inserts one Repeat key into keyboard buffer,\r
1896     //\r
1897     InsertKeyCode (\r
1898       &(UsbKeyboardDevice->KeyboardBuffer),\r
1899       UsbKeyboardDevice->RepeatKey,\r
1900       1\r
1901       );\r
1902 \r
1903     //\r
1904     // set repeate rate for repeat key generation.\r
1905     //\r
1906     gBS->SetTimer (\r
1907           UsbKeyboardDevice->RepeatTimer,\r
1908           TimerRelative,\r
1909           USBKBD_REPEAT_RATE\r
1910           );\r
1911 \r
1912   }\r
1913 }\r
1914 \r
1915 \r
1916 /**\r
1917   Timer handler for Delayed Recovery timer.\r
1918 \r
1919   @param  Event              The Delayed Recovery event.\r
1920   @param  Context            Points to the USB_KB_DEV instance.\r
1921 \r
1922 \r
1923 **/\r
1924 VOID\r
1925 EFIAPI\r
1926 USBKeyboardRecoveryHandler (\r
1927   IN    EFI_EVENT    Event,\r
1928   IN    VOID         *Context\r
1929   )\r
1930 {\r
1931 \r
1932   USB_KB_DEV          *UsbKeyboardDevice;\r
1933   EFI_USB_IO_PROTOCOL *UsbIo;\r
1934   UINT8               PacketSize;\r
1935 \r
1936   UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
1937 \r
1938   UsbIo             = UsbKeyboardDevice->UsbIo;\r
1939 \r
1940   PacketSize        = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);\r
1941 \r
1942   UsbIo->UsbAsyncInterruptTransfer (\r
1943           UsbIo,\r
1944           UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,\r
1945           TRUE,\r
1946           UsbKeyboardDevice->IntEndpointDescriptor.Interval,\r
1947           PacketSize,\r
1948           KeyboardHandler,\r
1949           UsbKeyboardDevice\r
1950           );\r
1951 }\r