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