]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
MdeModulePkg/UsbKb: ReadKeyStrokeEx always return key state
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / EfiKey.c
CommitLineData
ed838d0c 1/** @file\r
b4e73a63 2 USB Keyboard Driver that manages USB keyboard and produces Simple Text Input\r
3 Protocol and Simple Text Input Ex Protocol.\r
a7022cec 4\r
c095341c 5Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
d4a622c4 6This program and the accompanying materials\r
ed838d0c 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
a7022cec 14**/\r
ed838d0c 15\r
a7022cec 16#include "EfiKey.h"\r
17#include "KeyBoard.h"\r
ed838d0c 18\r
ed838d0c 19//\r
20// USB Keyboard Driver Global Variables\r
21//\r
22EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {\r
23 USBKeyboardDriverBindingSupported,\r
24 USBKeyboardDriverBindingStart,\r
25 USBKeyboardDriverBindingStop,\r
26 0xa,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
a7022cec 31/**\r
5899f27e 32 Entrypoint of USB Keyboard Driver.\r
33\r
34 This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding\r
35 Protocols together with Component Name Protocols.\r
a7022cec 36\r
5899f27e 37 @param ImageHandle The firmware allocated handle for the EFI image.\r
38 @param SystemTable A pointer to the EFI System Table.\r
a7022cec 39\r
5899f27e 40 @retval EFI_SUCCESS The entry point is executed successfully.\r
a7022cec 41\r
42**/\r
ed838d0c 43EFI_STATUS\r
44EFIAPI\r
45USBKeyboardDriverBindingEntryPoint (\r
46 IN EFI_HANDLE ImageHandle,\r
47 IN EFI_SYSTEM_TABLE *SystemTable\r
48 )\r
ed838d0c 49{\r
5899f27e 50 EFI_STATUS Status;\r
51\r
52 Status = EfiLibInstallDriverBindingComponentName2 (\r
53 ImageHandle,\r
54 SystemTable,\r
55 &gUsbKeyboardDriverBinding,\r
56 ImageHandle,\r
57 &gUsbKeyboardComponentName,\r
58 &gUsbKeyboardComponentName2\r
59 );\r
60 ASSERT_EFI_ERROR (Status);\r
61\r
62 return EFI_SUCCESS;\r
ed838d0c 63}\r
64\r
ed838d0c 65/**\r
5899f27e 66 Check whether USB keyboard driver supports this device.\r
ed838d0c 67\r
a7022cec 68 @param This The USB keyboard driver binding protocol.\r
69 @param Controller The controller handle to check.\r
70 @param RemainingDevicePath The remaining device path.\r
ed838d0c 71\r
a7022cec 72 @retval EFI_SUCCESS The driver supports this controller.\r
5899f27e 73 @retval other This device isn't supported.\r
74\r
ed838d0c 75**/\r
76EFI_STATUS\r
77EFIAPI\r
78USBKeyboardDriverBindingSupported (\r
79 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
80 IN EFI_HANDLE Controller,\r
81 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
82 )\r
83{\r
ed838d0c 84 EFI_STATUS Status;\r
5899f27e 85 EFI_USB_IO_PROTOCOL *UsbIo;\r
ed838d0c 86\r
87 //\r
5899f27e 88 // Check if USB I/O Protocol is attached on the controller handle.\r
ed838d0c 89 //\r
5899f27e 90 Status = gBS->OpenProtocol (\r
91 Controller,\r
92 &gEfiUsbIoProtocolGuid,\r
93 (VOID **) &UsbIo,\r
94 This->DriverBindingHandle,\r
95 Controller,\r
96 EFI_OPEN_PROTOCOL_BY_DRIVER\r
97 );\r
98 if (EFI_ERROR (Status)) {\r
99 return Status;\r
ed838d0c 100 }\r
101\r
102 //\r
b4e73a63 103 // Use the USB I/O Protocol interface to check whether Controller is\r
104 // a keyboard device that can be managed by this driver.\r
ed838d0c 105 //\r
106 Status = EFI_SUCCESS;\r
107\r
108 if (!IsUSBKeyboard (UsbIo)) {\r
109 Status = EFI_UNSUPPORTED;\r
110 }\r
111\r
112 gBS->CloseProtocol (\r
5899f27e 113 Controller,\r
114 &gEfiUsbIoProtocolGuid,\r
115 This->DriverBindingHandle,\r
116 Controller\r
117 );\r
ed838d0c 118\r
119 return Status;\r
120}\r
121\r
ed838d0c 122/**\r
c92e277d 123 Starts the keyboard device with this driver.\r
b4e73a63 124\r
125 This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,\r
126 initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage\r
127 this keyboard device.\r
ed838d0c 128\r
a7022cec 129 @param This The USB keyboard driver binding instance.\r
5899f27e 130 @param Controller Handle of device to bind driver to.\r
131 @param RemainingDevicePath Optional parameter use to pick a specific child\r
132 device to start.\r
ed838d0c 133\r
a7022cec 134 @retval EFI_SUCCESS The controller is controlled by the usb keyboard driver.\r
5899f27e 135 @retval EFI_UNSUPPORTED No interrupt endpoint can be found.\r
b4e73a63 136 @retval Other This controller cannot be started.\r
ed838d0c 137\r
138**/\r
139EFI_STATUS\r
140EFIAPI\r
141USBKeyboardDriverBindingStart (\r
142 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
143 IN EFI_HANDLE Controller,\r
144 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
145 )\r
146{\r
147 EFI_STATUS Status;\r
148 EFI_USB_IO_PROTOCOL *UsbIo;\r
149 USB_KB_DEV *UsbKeyboardDevice;\r
150 UINT8 EndpointNumber;\r
151 EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;\r
152 UINT8 Index;\r
153 UINT8 EndpointAddr;\r
154 UINT8 PollingInterval;\r
155 UINT8 PacketSize;\r
156 BOOLEAN Found;\r
15cc67e6 157 EFI_TPL OldTpl;\r
ed838d0c 158\r
15cc67e6 159 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
ed838d0c 160 //\r
5899f27e 161 // Open USB I/O Protocol\r
ed838d0c 162 //\r
163 Status = gBS->OpenProtocol (\r
164 Controller,\r
165 &gEfiUsbIoProtocolGuid,\r
c52fa98c 166 (VOID **) &UsbIo,\r
ed838d0c 167 This->DriverBindingHandle,\r
168 Controller,\r
169 EFI_OPEN_PROTOCOL_BY_DRIVER\r
170 );\r
171 if (EFI_ERROR (Status)) {\r
15cc67e6 172 goto ErrorExit1;\r
ed838d0c 173 }\r
174\r
175 UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));\r
5899f27e 176 ASSERT (UsbKeyboardDevice != NULL);\r
177\r
ed838d0c 178 //\r
179 // Get the Device Path Protocol on Controller's handle\r
180 //\r
181 Status = gBS->OpenProtocol (\r
182 Controller,\r
183 &gEfiDevicePathProtocolGuid,\r
184 (VOID **) &UsbKeyboardDevice->DevicePath,\r
185 This->DriverBindingHandle,\r
186 Controller,\r
187 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
188 );\r
189\r
190 if (EFI_ERROR (Status)) {\r
5899f27e 191 goto ErrorExit;\r
ed838d0c 192 }\r
193 //\r
5899f27e 194 // Report that the USB keyboard is being enabled\r
ed838d0c 195 //\r
5899f27e 196 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
ed838d0c 197 EFI_PROGRESS_CODE,\r
f9876ecf 198 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE),\r
5899f27e 199 UsbKeyboardDevice->DevicePath\r
ed838d0c 200 );\r
201\r
202 //\r
203 // This is pretty close to keyboard detection, so log progress\r
204 //\r
5899f27e 205 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
ed838d0c 206 EFI_PROGRESS_CODE,\r
f9876ecf 207 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT),\r
5899f27e 208 UsbKeyboardDevice->DevicePath\r
ed838d0c 209 );\r
210\r
ed838d0c 211 UsbKeyboardDevice->UsbIo = UsbIo;\r
212\r
213 //\r
214 // Get interface & endpoint descriptor\r
215 //\r
216 UsbIo->UsbGetInterfaceDescriptor (\r
5899f27e 217 UsbIo,\r
218 &UsbKeyboardDevice->InterfaceDescriptor\r
219 );\r
ed838d0c 220\r
221 EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;\r
222\r
5899f27e 223 //\r
c92e277d 224 // Traverse endpoints to find interrupt endpoint\r
5899f27e 225 //\r
226 Found = FALSE;\r
ed838d0c 227 for (Index = 0; Index < EndpointNumber; Index++) {\r
228\r
229 UsbIo->UsbGetEndpointDescriptor (\r
5899f27e 230 UsbIo,\r
231 Index,\r
232 &EndpointDescriptor\r
233 );\r
ed838d0c 234\r
c92e277d 235 if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) {\r
ed838d0c 236 //\r
237 // We only care interrupt endpoint here\r
238 //\r
84b5c78e 239 CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));\r
ed838d0c 240 Found = TRUE;\r
5899f27e 241 break;\r
ed838d0c 242 }\r
243 }\r
244\r
245 if (!Found) {\r
246 //\r
37623a5c 247 // Report Status Code to indicate that there is no USB keyboard\r
248 //\r
249 REPORT_STATUS_CODE (\r
250 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
251 (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)\r
252 );\r
253 //\r
ed838d0c 254 // No interrupt endpoint found, then return unsupported.\r
255 //\r
5899f27e 256 Status = EFI_UNSUPPORTED;\r
257 goto ErrorExit;\r
ed838d0c 258 }\r
259\r
37623a5c 260 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
261 EFI_PROGRESS_CODE,\r
262 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),\r
263 UsbKeyboardDevice->DevicePath\r
264 );\r
265\r
ed838d0c 266 UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE;\r
267 UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset;\r
268 UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke;\r
66aa04e4 269\r
270 UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx;\r
271 UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx;\r
272 UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState;\r
273 UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify;\r
c41c3e55 274 UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;\r
3765794c 275\r
66aa04e4 276 InitializeListHead (&UsbKeyboardDevice->NotifyList);\r
3765794c 277\r
c1fd2767
RN
278 Status = gBS->CreateEvent (\r
279 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
280 TPL_NOTIFY,\r
281 USBKeyboardTimerHandler,\r
282 UsbKeyboardDevice,\r
283 &UsbKeyboardDevice->TimerEvent\r
284 );\r
285 if (!EFI_ERROR (Status)) {\r
286 Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL);\r
287 }\r
288 if (EFI_ERROR (Status)) {\r
289 goto ErrorExit;\r
290 }\r
291\r
66aa04e4 292 Status = gBS->CreateEvent (\r
293 EVT_NOTIFY_WAIT,\r
294 TPL_NOTIFY,\r
295 USBKeyboardWaitForKey,\r
296 UsbKeyboardDevice,\r
297 &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)\r
298 );\r
299\r
300 if (EFI_ERROR (Status)) {\r
301 goto ErrorExit;\r
302 }\r
303\r
ed838d0c 304 Status = gBS->CreateEvent (\r
305 EVT_NOTIFY_WAIT,\r
306 TPL_NOTIFY,\r
307 USBKeyboardWaitForKey,\r
308 UsbKeyboardDevice,\r
309 &(UsbKeyboardDevice->SimpleInput.WaitForKey)\r
310 );\r
5899f27e 311 if (EFI_ERROR (Status)) {\r
312 goto ErrorExit;\r
ed838d0c 313 }\r
314\r
4ae46dba
SZ
315 Status = gBS->CreateEvent (\r
316 EVT_NOTIFY_SIGNAL,\r
317 TPL_CALLBACK,\r
318 KeyNotifyProcessHandler,\r
319 UsbKeyboardDevice,\r
320 &UsbKeyboardDevice->KeyNotifyProcessEvent\r
321 );\r
322 if (EFI_ERROR (Status)) {\r
323 goto ErrorExit;\r
324 }\r
325\r
ed838d0c 326 //\r
5899f27e 327 // Install Simple Text Input Protocol and Simple Text Input Ex Protocol\r
328 // for the USB keyboard device.\r
329 // USB keyboard is a hot plug device, and expected to work immediately\r
aa8f4f55 330 // when plugging into system, other conventional console devices could\r
331 // distinguish it by its device path.\r
ed838d0c 332 //\r
333 Status = gBS->InstallMultipleProtocolInterfaces (\r
334 &Controller,\r
335 &gEfiSimpleTextInProtocolGuid,\r
336 &UsbKeyboardDevice->SimpleInput,\r
66aa04e4 337 &gEfiSimpleTextInputExProtocolGuid,\r
338 &UsbKeyboardDevice->SimpleInputEx,\r
ed838d0c 339 NULL\r
340 );\r
341 if (EFI_ERROR (Status)) {\r
5899f27e 342 goto ErrorExit;\r
ed838d0c 343 }\r
344\r
c41c3e55 345 UsbKeyboardDevice->ControllerHandle = Controller;\r
346 Status = InitKeyboardLayout (UsbKeyboardDevice);\r
347 if (EFI_ERROR (Status)) {\r
348 gBS->UninstallMultipleProtocolInterfaces (\r
349 Controller,\r
350 &gEfiSimpleTextInProtocolGuid,\r
351 &UsbKeyboardDevice->SimpleInput,\r
352 &gEfiSimpleTextInputExProtocolGuid,\r
353 &UsbKeyboardDevice->SimpleInputEx,\r
354 NULL\r
355 );\r
356 goto ErrorExit;\r
357 }\r
358\r
359\r
ed838d0c 360 //\r
5899f27e 361 // Reset USB Keyboard Device exhaustively.\r
ed838d0c 362 //\r
d4a622c4 363 Status = UsbKeyboardDevice->SimpleInputEx.Reset (\r
364 &UsbKeyboardDevice->SimpleInputEx,\r
ed838d0c 365 TRUE\r
366 );\r
367 if (EFI_ERROR (Status)) {\r
368 gBS->UninstallMultipleProtocolInterfaces (\r
66aa04e4 369 Controller,\r
370 &gEfiSimpleTextInProtocolGuid,\r
371 &UsbKeyboardDevice->SimpleInput,\r
372 &gEfiSimpleTextInputExProtocolGuid,\r
373 &UsbKeyboardDevice->SimpleInputEx,\r
66aa04e4 374 NULL\r
375 );\r
5899f27e 376 goto ErrorExit;\r
ed838d0c 377 }\r
5899f27e 378\r
ed838d0c 379 //\r
5899f27e 380 // Submit Asynchronous Interrupt Transfer to manage this device.\r
ed838d0c 381 //\r
382 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;\r
383 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;\r
384 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);\r
385\r
386 Status = UsbIo->UsbAsyncInterruptTransfer (\r
387 UsbIo,\r
388 EndpointAddr,\r
389 TRUE,\r
390 PollingInterval,\r
391 PacketSize,\r
392 KeyboardHandler,\r
393 UsbKeyboardDevice\r
394 );\r
395\r
396 if (EFI_ERROR (Status)) {\r
ed838d0c 397 gBS->UninstallMultipleProtocolInterfaces (\r
66aa04e4 398 Controller,\r
399 &gEfiSimpleTextInProtocolGuid,\r
400 &UsbKeyboardDevice->SimpleInput,\r
401 &gEfiSimpleTextInputExProtocolGuid,\r
402 &UsbKeyboardDevice->SimpleInputEx,\r
66aa04e4 403 NULL\r
404 );\r
5899f27e 405 goto ErrorExit;\r
ed838d0c 406 }\r
407\r
408 UsbKeyboardDevice->ControllerNameTable = NULL;\r
62b9bb55 409 AddUnicodeString2 (\r
ed838d0c 410 "eng",\r
411 gUsbKeyboardComponentName.SupportedLanguages,\r
412 &UsbKeyboardDevice->ControllerNameTable,\r
62b9bb55 413 L"Generic Usb Keyboard",\r
414 TRUE\r
ed838d0c 415 );\r
62b9bb55 416 AddUnicodeString2 (\r
417 "en",\r
418 gUsbKeyboardComponentName2.SupportedLanguages,\r
419 &UsbKeyboardDevice->ControllerNameTable,\r
420 L"Generic Usb Keyboard",\r
421 FALSE\r
422 );\r
423\r
15cc67e6 424 gBS->RestoreTPL (OldTpl);\r
ed838d0c 425 return EFI_SUCCESS;\r
66aa04e4 426\r
5899f27e 427//\r
428// Error handler\r
429//\r
66aa04e4 430ErrorExit:\r
431 if (UsbKeyboardDevice != NULL) {\r
c1fd2767
RN
432 if (UsbKeyboardDevice->TimerEvent != NULL) {\r
433 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);\r
434 }\r
66aa04e4 435 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {\r
436 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
437 }\r
438 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
439 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
440 }\r
4ae46dba
SZ
441 if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {\r
442 gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
443 }\r
16a97771 444 if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {\r
ea021002 445 ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
16a97771 446 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
447 }\r
c92e277d 448 FreePool (UsbKeyboardDevice);\r
66aa04e4 449 UsbKeyboardDevice = NULL;\r
450 }\r
451 gBS->CloseProtocol (\r
452 Controller,\r
453 &gEfiUsbIoProtocolGuid,\r
454 This->DriverBindingHandle,\r
455 Controller\r
456 );\r
15cc67e6 457\r
458ErrorExit1:\r
459 gBS->RestoreTPL (OldTpl);\r
460\r
66aa04e4 461 return Status;\r
462\r
ed838d0c 463}\r
464\r
465\r
ed838d0c 466/**\r
b4e73a63 467 Stop the USB keyboard device handled by this driver.\r
ed838d0c 468\r
a7022cec 469 @param This The USB keyboard driver binding protocol.\r
470 @param Controller The controller to release.\r
471 @param NumberOfChildren The number of handles in ChildHandleBuffer.\r
472 @param ChildHandleBuffer The array of child handle.\r
ed838d0c 473\r
b4e73a63 474 @retval EFI_SUCCESS The device was stopped.\r
5899f27e 475 @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol\r
476 is not installed on Controller.\r
b4e73a63 477 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
478 @retval Others Fail to uninstall protocols attached on the device.\r
ed838d0c 479\r
480**/\r
481EFI_STATUS\r
482EFIAPI\r
483USBKeyboardDriverBindingStop (\r
484 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
485 IN EFI_HANDLE Controller,\r
486 IN UINTN NumberOfChildren,\r
487 IN EFI_HANDLE *ChildHandleBuffer\r
488 )\r
489{\r
5899f27e 490 EFI_STATUS Status;\r
ed838d0c 491 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;\r
5899f27e 492 USB_KB_DEV *UsbKeyboardDevice;\r
ed838d0c 493\r
494 Status = gBS->OpenProtocol (\r
495 Controller,\r
496 &gEfiSimpleTextInProtocolGuid,\r
c52fa98c 497 (VOID **) &SimpleInput,\r
ed838d0c 498 This->DriverBindingHandle,\r
499 Controller,\r
bcb9d421 500 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
ed838d0c 501 );\r
502 if (EFI_ERROR (Status)) {\r
503 return EFI_UNSUPPORTED;\r
504 }\r
5899f27e 505\r
66aa04e4 506 Status = gBS->OpenProtocol (\r
507 Controller,\r
508 &gEfiSimpleTextInputExProtocolGuid,\r
509 NULL,\r
510 This->DriverBindingHandle,\r
511 Controller,\r
512 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
513 );\r
514 if (EFI_ERROR (Status)) {\r
515 return EFI_UNSUPPORTED;\r
516 }\r
b4e73a63 517\r
ed838d0c 518 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);\r
519\r
ed838d0c 520 //\r
5899f27e 521 // The key data input from this device will be disabled.\r
ed838d0c 522 //\r
5899f27e 523 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
ed838d0c 524 EFI_PROGRESS_CODE,\r
f9876ecf 525 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),\r
5899f27e 526 UsbKeyboardDevice->DevicePath\r
ed838d0c 527 );\r
528\r
529 //\r
5899f27e 530 // Delete the Asynchronous Interrupt Transfer from this device\r
ed838d0c 531 //\r
532 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (\r
533 UsbKeyboardDevice->UsbIo,\r
534 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,\r
535 FALSE,\r
536 UsbKeyboardDevice->IntEndpointDescriptor.Interval,\r
537 0,\r
538 NULL,\r
539 NULL\r
540 );\r
541\r
542 gBS->CloseProtocol (\r
5899f27e 543 Controller,\r
544 &gEfiUsbIoProtocolGuid,\r
545 This->DriverBindingHandle,\r
546 Controller\r
547 );\r
ed838d0c 548\r
549 Status = gBS->UninstallMultipleProtocolInterfaces (\r
550 Controller,\r
551 &gEfiSimpleTextInProtocolGuid,\r
552 &UsbKeyboardDevice->SimpleInput,\r
66aa04e4 553 &gEfiSimpleTextInputExProtocolGuid,\r
554 &UsbKeyboardDevice->SimpleInputEx,\r
ed838d0c 555 NULL\r
556 );\r
557 //\r
5899f27e 558 // Free all resources.\r
ed838d0c 559 //\r
c1fd2767 560 gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);\r
ed838d0c 561 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);\r
562 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);\r
c1fd2767
RN
563 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
564 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
4ae46dba 565 gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
c1fd2767 566 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);\r
ed838d0c 567\r
813acf3a 568 ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
569 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
570\r
ed838d0c 571 if (UsbKeyboardDevice->ControllerNameTable != NULL) {\r
572 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);\r
573 }\r
574\r
c1fd2767
RN
575 DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);\r
576 DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);\r
4ae46dba 577 DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);\r
3765794c 578\r
c92e277d 579 FreePool (UsbKeyboardDevice);\r
ed838d0c 580\r
581 return Status;\r
ed838d0c 582}\r
583\r
a7022cec 584/**\r
b4e73a63 585 Internal function to read the next keystroke from the keyboard buffer.\r
a7022cec 586\r
b4e73a63 587 @param UsbKeyboardDevice USB keyboard's private structure.\r
588 @param KeyData A pointer to buffer to hold the keystroke\r
589 data for the key that was pressed.\r
a7022cec 590\r
b4e73a63 591 @retval EFI_SUCCESS The keystroke information was returned.\r
592 @retval EFI_NOT_READY There was no keystroke data availiable.\r
593 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
a7022cec 594 hardware errors.\r
b4e73a63 595 @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
596 @retval Others Fail to translate keycode into EFI_INPUT_KEY\r
a7022cec 597\r
598**/\r
66aa04e4 599EFI_STATUS\r
600USBKeyboardReadKeyStrokeWorker (\r
b4e73a63 601 IN OUT USB_KB_DEV *UsbKeyboardDevice,\r
602 OUT EFI_KEY_DATA *KeyData\r
66aa04e4 603 )\r
66aa04e4 604{\r
66aa04e4 605 if (KeyData == NULL) {\r
606 return EFI_INVALID_PARAMETER;\r
607 }\r
608\r
c1fd2767 609 if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
c095341c
RN
610 ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
611 InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState);\r
c1fd2767 612 return EFI_NOT_READY;\r
66aa04e4 613 }\r
614\r
c1fd2767 615 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));\r
66aa04e4 616\r
617 return EFI_SUCCESS;\r
66aa04e4 618}\r
a7022cec 619\r
620/**\r
e15c65a3 621 Reset the input device and optionally run diagnostics\r
5899f27e 622\r
623 There are 2 types of reset for USB keyboard.\r
624 For non-exhaustive reset, only keyboard buffer is cleared.\r
625 For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status\r
626 is also re-initialized.\r
a7022cec 627\r
b4e73a63 628 @param This Protocol instance pointer.\r
629 @param ExtendedVerification Driver may perform diagnostics on reset.\r
a7022cec 630\r
b4e73a63 631 @retval EFI_SUCCESS The device was reset.\r
632 @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset.\r
a7022cec 633\r
634**/\r
ed838d0c 635EFI_STATUS\r
636EFIAPI\r
637USBKeyboardReset (\r
638 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
5899f27e 639 IN BOOLEAN ExtendedVerification\r
ed838d0c 640 )\r
641{\r
642 EFI_STATUS Status;\r
643 USB_KB_DEV *UsbKeyboardDevice;\r
ed838d0c 644\r
645 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);\r
646\r
5899f27e 647 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
ed838d0c 648 EFI_PROGRESS_CODE,\r
f9876ecf 649 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),\r
5899f27e 650 UsbKeyboardDevice->DevicePath\r
ed838d0c 651 );\r
652\r
653 //\r
5899f27e 654 // Non-exhaustive reset:\r
ed838d0c 655 // only reset private data structures.\r
656 //\r
657 if (!ExtendedVerification) {\r
5899f27e 658 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
ed838d0c 659 EFI_PROGRESS_CODE,\r
f9876ecf 660 (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),\r
5899f27e 661 UsbKeyboardDevice->DevicePath\r
ed838d0c 662 );\r
5899f27e 663 //\r
664 // Clear the key buffer of this USB keyboard\r
665 //\r
c1fd2767
RN
666 InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));\r
667 InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));\r
4ae46dba 668 InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));\r
5899f27e 669\r
ed838d0c 670 return EFI_SUCCESS;\r
671 }\r
672\r
673 //\r
674 // Exhaustive reset\r
675 //\r
5899f27e 676 Status = InitUSBKeyboard (UsbKeyboardDevice);\r
ed838d0c 677 if (EFI_ERROR (Status)) {\r
678 return EFI_DEVICE_ERROR;\r
679 }\r
680\r
681 return EFI_SUCCESS;\r
682}\r
683\r
684\r
685/**\r
b4e73a63 686 Reads the next keystroke from the input device.\r
ed838d0c 687\r
a7022cec 688 @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.\r
689 @param Key A pointer to a buffer that is filled in with the keystroke\r
690 information for the key that was pressed.\r
ed838d0c 691\r
b4e73a63 692 @retval EFI_SUCCESS The keystroke information was returned.\r
693 @retval EFI_NOT_READY There was no keystroke data availiable.\r
e15c65a3 694 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
b4e73a63 695 hardware errors.\r
ed838d0c 696\r
697**/\r
ed838d0c 698EFI_STATUS\r
699EFIAPI\r
700USBKeyboardReadKeyStroke (\r
701 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
5899f27e 702 OUT EFI_INPUT_KEY *Key\r
ed838d0c 703 )\r
704{\r
66aa04e4 705 USB_KB_DEV *UsbKeyboardDevice;\r
706 EFI_STATUS Status;\r
707 EFI_KEY_DATA KeyData;\r
ed838d0c 708\r
709 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);\r
710\r
3765794c 711 //\r
712 // Considering if the partial keystroke is enabled, there maybe a partial\r
713 // keystroke in the queue, so here skip the partial keystroke and get the\r
714 // next key from the queue\r
715 //\r
716 while (1) {\r
717 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);\r
718 if (EFI_ERROR (Status)) {\r
719 return Status;\r
720 }\r
721 //\r
722 // SimpleTextIn Protocol doesn't support partial keystroke;\r
723 //\r
724 if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {\r
725 continue;\r
726 }\r
608817ad
RN
727 //\r
728 // Translate the CTRL-Alpha characters to their corresponding control value\r
729 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)\r
730 //\r
731 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
732 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
733 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
734 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
735 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
736 }\r
737 }\r
738\r
3765794c 739 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
740 return EFI_SUCCESS;\r
ed838d0c 741 }\r
ed838d0c 742}\r
743\r
744\r
745/**\r
b4e73a63 746 Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx\r
747 and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.\r
ed838d0c 748\r
a7022cec 749 @param Event Event to be signaled when a key is pressed.\r
750 @param Context Points to USB_KB_DEV instance.\r
ed838d0c 751\r
752**/\r
ed838d0c 753VOID\r
754EFIAPI\r
755USBKeyboardWaitForKey (\r
756 IN EFI_EVENT Event,\r
757 IN VOID *Context\r
758 )\r
759{\r
760 USB_KB_DEV *UsbKeyboardDevice;\r
3765794c 761 EFI_KEY_DATA KeyData;\r
762 EFI_TPL OldTpl;\r
ed838d0c 763\r
764 UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
765\r
3765794c 766 //\r
767 // Enter critical section\r
768 // \r
769 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
770 \r
771 //\r
772 // WaitforKey doesn't suppor the partial key.\r
773 // Considering if the partial keystroke is enabled, there maybe a partial\r
774 // keystroke in the queue, so here skip the partial keystroke and get the\r
775 // next key from the queue\r
776 //\r
777 while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
c1fd2767
RN
778 //\r
779 // If there is pending key, signal the event.\r
780 //\r
3765794c 781 CopyMem (\r
782 &KeyData,\r
783 UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],\r
784 sizeof (EFI_KEY_DATA)\r
785 );\r
786 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
787 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));\r
788 continue;\r
789 }\r
c1fd2767 790 gBS->SignalEvent (Event);\r
3765794c 791 break;\r
ed838d0c 792 }\r
3765794c 793 //\r
794 // Leave critical section and return\r
795 //\r
796 gBS->RestoreTPL (OldTpl);\r
ed838d0c 797}\r
798\r
ed838d0c 799/**\r
c1fd2767 800 Timer handler to convert the key from USB.\r
ed838d0c 801\r
c1fd2767
RN
802 @param Event Indicates the event that invoke this function.\r
803 @param Context Indicates the calling context.\r
ed838d0c 804**/\r
c1fd2767 805VOID\r
a7022cec 806EFIAPI\r
c1fd2767
RN
807USBKeyboardTimerHandler (\r
808 IN EFI_EVENT Event,\r
809 IN VOID *Context\r
ed838d0c 810 )\r
811{\r
c1fd2767
RN
812 EFI_STATUS Status;\r
813 USB_KB_DEV *UsbKeyboardDevice;\r
814 UINT8 KeyCode;\r
815 EFI_KEY_DATA KeyData;\r
ed838d0c 816\r
c1fd2767 817 UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
3765794c 818\r
ed838d0c 819 //\r
b4e73a63 820 // Fetch raw data from the USB keyboard buffer,\r
821 // and translate it into USB keycode.\r
ed838d0c 822 //\r
b4e73a63 823 Status = USBParseKey (UsbKeyboardDevice, &KeyCode);\r
ed838d0c 824 if (EFI_ERROR (Status)) {\r
c1fd2767 825 return ;\r
ed838d0c 826 }\r
827\r
c1fd2767
RN
828 //\r
829 // Translate saved USB keycode into EFI_INPUT_KEY\r
830 //\r
831 Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);\r
832 if (EFI_ERROR (Status)) {\r
833 return ;\r
834 }\r
835\r
836 //\r
837 // Insert to the EFI Key queue\r
838 //\r
839 Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));\r
ed838d0c 840}\r
841\r
a7022cec 842/**\r
843 Free keyboard notify list.\r
66aa04e4 844\r
b4e73a63 845 @param NotifyList The keyboard notify list to free.\r
66aa04e4 846\r
a7022cec 847 @retval EFI_SUCCESS Free the notify list successfully.\r
b4e73a63 848 @retval EFI_INVALID_PARAMETER NotifyList is NULL.\r
66aa04e4 849\r
a7022cec 850**/\r
851EFI_STATUS\r
a7022cec 852KbdFreeNotifyList (\r
b4e73a63 853 IN OUT LIST_ENTRY *NotifyList\r
a7022cec 854 )\r
66aa04e4 855{\r
856 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
b4e73a63 857 LIST_ENTRY *Link;\r
66aa04e4 858\r
b4e73a63 859 if (NotifyList == NULL) {\r
66aa04e4 860 return EFI_INVALID_PARAMETER;\r
861 }\r
b4e73a63 862 while (!IsListEmpty (NotifyList)) {\r
863 Link = GetFirstNode (NotifyList);\r
864 NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
865 RemoveEntryList (Link);\r
c92e277d 866 FreePool (NotifyNode);\r
66aa04e4 867 }\r
3765794c 868\r
66aa04e4 869 return EFI_SUCCESS;\r
870}\r
871\r
a7022cec 872/**\r
b4e73a63 873 Check whether the pressed key matches a registered key or not.\r
a7022cec 874\r
b4e73a63 875 @param RegsiteredData A pointer to keystroke data for the key that was registered.\r
876 @param InputData A pointer to keystroke data for the key that was pressed.\r
a7022cec 877\r
878 @retval TRUE Key pressed matches a registered key.\r
e15c65a3 879 @retval FLASE Key pressed does not matches a registered key.\r
a7022cec 880\r
881**/\r
66aa04e4 882BOOLEAN\r
883IsKeyRegistered (\r
884 IN EFI_KEY_DATA *RegsiteredData,\r
885 IN EFI_KEY_DATA *InputData\r
886 )\r
66aa04e4 887{\r
888 ASSERT (RegsiteredData != NULL && InputData != NULL);\r
3765794c 889\r
66aa04e4 890 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||\r
891 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
3765794c 892 return FALSE;\r
893 }\r
894\r
66aa04e4 895 //\r
896 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
897 //\r
898 if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
899 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
3765794c 900 return FALSE;\r
901 }\r
66aa04e4 902 if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
903 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
3765794c 904 return FALSE;\r
905 }\r
906\r
66aa04e4 907 return TRUE;\r
66aa04e4 908}\r
909\r
910//\r
3765794c 911// Simple Text Input Ex protocol functions\r
66aa04e4 912//\r
a7022cec 913/**\r
b4e73a63 914 Resets the input device hardware.\r
915\r
916 The Reset() function resets the input device hardware. As part\r
917 of initialization process, the firmware/device will make a quick\r
918 but reasonable attempt to verify that the device is functioning.\r
919 If the ExtendedVerification flag is TRUE the firmware may take\r
920 an extended amount of time to verify the device is operating on\r
921 reset. Otherwise the reset operation is to occur as quickly as\r
922 possible. The hardware verification process is not defined by\r
923 this specification and is left up to the platform firmware or\r
924 driver to implement.\r
a7022cec 925\r
b4e73a63 926 @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.\r
a7022cec 927\r
b4e73a63 928 @param ExtendedVerification Indicates that the driver may perform a more exhaustive\r
929 verification operation of the device during reset.\r
930\r
931 @retval EFI_SUCCESS The device was reset.\r
932 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.\r
a7022cec 933\r
934**/\r
66aa04e4 935EFI_STATUS\r
936EFIAPI\r
937USBKeyboardResetEx (\r
938 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
939 IN BOOLEAN ExtendedVerification\r
940 )\r
66aa04e4 941{\r
942 EFI_STATUS Status;\r
943 USB_KB_DEV *UsbKeyboardDevice;\r
66aa04e4 944\r
945 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
946\r
947 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);\r
948 if (EFI_ERROR (Status)) {\r
949 return EFI_DEVICE_ERROR;\r
950 }\r
951\r
3765794c 952 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;\r
953 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
954\r
66aa04e4 955 return EFI_SUCCESS;\r
956\r
957}\r
958\r
a7022cec 959/**\r
b4e73a63 960 Reads the next keystroke from the input device.\r
a7022cec 961\r
b4e73a63 962 @param This Protocol instance pointer.\r
963 @param KeyData A pointer to a buffer that is filled in with the keystroke\r
964 state data for the key that was pressed.\r
a7022cec 965\r
b4e73a63 966 @retval EFI_SUCCESS The keystroke information was returned.\r
967 @retval EFI_NOT_READY There was no keystroke data available.\r
968 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
969 hardware errors.\r
970 @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
a7022cec 971\r
972**/\r
66aa04e4 973EFI_STATUS\r
974EFIAPI\r
975USBKeyboardReadKeyStrokeEx (\r
976 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
977 OUT EFI_KEY_DATA *KeyData\r
978 )\r
66aa04e4 979{\r
980 USB_KB_DEV *UsbKeyboardDevice;\r
981\r
982 if (KeyData == NULL) {\r
983 return EFI_INVALID_PARAMETER;\r
984 }\r
985\r
986 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
987\r
988 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);\r
3765794c 989\r
66aa04e4 990}\r
991\r
a7022cec 992/**\r
993 Set certain state for the input device.\r
994\r
995 @param This Protocol instance pointer.\r
996 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
997 state for the input device.\r
998\r
b4e73a63 999 @retval EFI_SUCCESS The device state was set appropriately.\r
1000 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could\r
1001 not have the setting adjusted.\r
1002 @retval EFI_UNSUPPORTED The device does not support the ability to have its state set.\r
a7022cec 1003 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.\r
1004\r
1005**/\r
66aa04e4 1006EFI_STATUS\r
1007EFIAPI\r
1008USBKeyboardSetState (\r
1009 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
1010 IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
1011 )\r
66aa04e4 1012{\r
1013 USB_KB_DEV *UsbKeyboardDevice;\r
1014\r
1015 if (KeyToggleState == NULL) {\r
1016 return EFI_INVALID_PARAMETER;\r
1017 }\r
1018\r
1019 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
1020\r
3765794c 1021 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||\r
1022 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {\r
66aa04e4 1023 return EFI_UNSUPPORTED;\r
1024 }\r
1025\r
1026 //\r
1027 // Update the status light\r
1028 //\r
1029\r
b4e73a63 1030 UsbKeyboardDevice->ScrollOn = FALSE;\r
1031 UsbKeyboardDevice->NumLockOn = FALSE;\r
1032 UsbKeyboardDevice->CapsOn = FALSE;\r
3765794c 1033 UsbKeyboardDevice->IsSupportPartialKey = FALSE;\r
1034\r
66aa04e4 1035 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
b4e73a63 1036 UsbKeyboardDevice->ScrollOn = TRUE;\r
66aa04e4 1037 }\r
1038 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
b4e73a63 1039 UsbKeyboardDevice->NumLockOn = TRUE;\r
66aa04e4 1040 }\r
1041 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
b4e73a63 1042 UsbKeyboardDevice->CapsOn = TRUE;\r
66aa04e4 1043 }\r
3765794c 1044 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
1045 UsbKeyboardDevice->IsSupportPartialKey = TRUE;\r
1046 }\r
66aa04e4 1047\r
1048 SetKeyLED (UsbKeyboardDevice);\r
1049\r
3765794c 1050 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;\r
1051\r
66aa04e4 1052 return EFI_SUCCESS;\r
3765794c 1053\r
66aa04e4 1054}\r
1055\r
a7022cec 1056/**\r
1057 Register a notification function for a particular keystroke for the input device.\r
1058\r
1059 @param This Protocol instance pointer.\r
3652f990
DB
1060 @param KeyData A pointer to a buffer that is filled in with\r
1061 the keystroke information for the key that was\r
1062 pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState\r
1063 and KeyData.KeyState.KeyShiftState are 0, then any incomplete\r
1064 keystroke will trigger a notification of the KeyNotificationFunction.\r
a7022cec 1065 @param KeyNotificationFunction Points to the function to be called when the key\r
3652f990
DB
1066 sequence is typed specified by KeyData. This notification function\r
1067 should be called at <=TPL_CALLBACK.\r
a7022cec 1068 @param NotifyHandle Points to the unique handle assigned to the registered notification.\r
1069\r
1070 @retval EFI_SUCCESS The notification function was registered successfully.\r
e15c65a3 1071 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.\r
b4e73a63 1072 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.\r
a7022cec 1073\r
1074**/\r
66aa04e4 1075EFI_STATUS\r
1076EFIAPI\r
1077USBKeyboardRegisterKeyNotify (\r
1078 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
1079 IN EFI_KEY_DATA *KeyData,\r
1080 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,\r
402e4a9d 1081 OUT VOID **NotifyHandle\r
66aa04e4 1082 )\r
66aa04e4 1083{\r
1084 USB_KB_DEV *UsbKeyboardDevice;\r
66aa04e4 1085 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;\r
1086 LIST_ENTRY *Link;\r
e15c65a3 1087 LIST_ENTRY *NotifyList;\r
3765794c 1088 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
66aa04e4 1089\r
1090 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
1091 return EFI_INVALID_PARAMETER;\r
1092 }\r
1093\r
1094 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
1095\r
1096 //\r
1097 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
1098 //\r
e15c65a3 1099 NotifyList = &UsbKeyboardDevice->NotifyList;\r
3765794c 1100\r
e15c65a3 1101 for (Link = GetFirstNode (NotifyList);\r
1102 !IsNull (NotifyList, Link);\r
1103 Link = GetNextNode (NotifyList, Link)) {\r
66aa04e4 1104 CurrentNotify = CR (\r
3765794c 1105 Link,\r
1106 KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
1107 NotifyEntry,\r
66aa04e4 1108 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
1109 );\r
3765794c 1110 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
66aa04e4 1111 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
402e4a9d 1112 *NotifyHandle = CurrentNotify;\r
66aa04e4 1113 return EFI_SUCCESS;\r
1114 }\r
1115 }\r
1116 }\r
3765794c 1117\r
66aa04e4 1118 //\r
1119 // Allocate resource to save the notification function\r
3765794c 1120 //\r
66aa04e4 1121 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
1122 if (NewNotify == NULL) {\r
1123 return EFI_OUT_OF_RESOURCES;\r
1124 }\r
1125\r
3765794c 1126 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
66aa04e4 1127 NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
1128 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
1129 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);\r
1130\r
7fc80d44 1131\r
402e4a9d 1132 *NotifyHandle = NewNotify;\r
3765794c 1133\r
66aa04e4 1134 return EFI_SUCCESS;\r
3765794c 1135\r
66aa04e4 1136}\r
1137\r
a7022cec 1138/**\r
1139 Remove a registered notification function from a particular keystroke.\r
1140\r
1141 @param This Protocol instance pointer.\r
1142 @param NotificationHandle The handle of the notification function being unregistered.\r
1143\r
1144 @retval EFI_SUCCESS The notification function was unregistered successfully.\r
b4e73a63 1145 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid\r
a7022cec 1146\r
1147**/\r
66aa04e4 1148EFI_STATUS\r
1149EFIAPI\r
1150USBKeyboardUnregisterKeyNotify (\r
1151 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
402e4a9d 1152 IN VOID *NotificationHandle\r
66aa04e4 1153 )\r
66aa04e4 1154{\r
1155 USB_KB_DEV *UsbKeyboardDevice;\r
66aa04e4 1156 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
1157 LIST_ENTRY *Link;\r
e15c65a3 1158 LIST_ENTRY *NotifyList;\r
66aa04e4 1159\r
1160 if (NotificationHandle == NULL) {\r
1161 return EFI_INVALID_PARAMETER;\r
3765794c 1162 }\r
0dc99784 1163\r
66aa04e4 1164 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
3765794c 1165\r
5899f27e 1166 //\r
1167 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.\r
1168 //\r
e15c65a3 1169 NotifyList = &UsbKeyboardDevice->NotifyList;\r
1170 for (Link = GetFirstNode (NotifyList);\r
1171 !IsNull (NotifyList, Link);\r
1172 Link = GetNextNode (NotifyList, Link)) {\r
66aa04e4 1173 CurrentNotify = CR (\r
3765794c 1174 Link,\r
1175 KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
1176 NotifyEntry,\r
66aa04e4 1177 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
3765794c 1178 );\r
402e4a9d 1179 if (CurrentNotify == NotificationHandle) {\r
66aa04e4 1180 //\r
1181 // Remove the notification function from NotifyList and free resources\r
1182 //\r
3765794c 1183 RemoveEntryList (&CurrentNotify->NotifyEntry);\r
7fc80d44 1184\r
3765794c 1185 FreePool (CurrentNotify);\r
66aa04e4 1186 return EFI_SUCCESS;\r
1187 }\r
1188 }\r
1189\r
8a67d804 1190 //\r
1191 // Cannot find the matching entry in database.\r
1192 //\r
3765794c 1193 return EFI_INVALID_PARAMETER;\r
66aa04e4 1194}\r
1195\r
4ae46dba
SZ
1196/**\r
1197 Process key notify.\r
1198\r
1199 @param Event Indicates the event that invoke this function.\r
1200 @param Context Indicates the calling context.\r
1201**/\r
1202VOID\r
1203EFIAPI\r
1204KeyNotifyProcessHandler (\r
1205 IN EFI_EVENT Event,\r
1206 IN VOID *Context\r
1207 )\r
1208{\r
1209 EFI_STATUS Status;\r
1210 USB_KB_DEV *UsbKeyboardDevice;\r
1211 EFI_KEY_DATA KeyData;\r
1212 LIST_ENTRY *Link;\r
1213 LIST_ENTRY *NotifyList;\r
1214 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
1215 EFI_TPL OldTpl;\r
1216\r
1217 UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
1218\r
1219 //\r
1220 // Invoke notification functions.\r
1221 //\r
1222 NotifyList = &UsbKeyboardDevice->NotifyList;\r
1223 while (TRUE) {\r
1224 //\r
1225 // Enter critical section\r
1226 // \r
1227 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1228 Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));\r
1229 //\r
1230 // Leave critical section\r
1231 //\r
1232 gBS->RestoreTPL (OldTpl);\r
1233 if (EFI_ERROR (Status)) {\r
1234 break;\r
1235 }\r
1236 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
1237 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
1238 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
1239 CurrentNotify->KeyNotificationFn (&KeyData);\r
1240 }\r
1241 }\r
1242 }\r
1243}\r
1244\r