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