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