]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
1. Retired HotPlugDevice protocol.
[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 - 2008, 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 PcdGet32 (PcdStatusCodeValueKeyboardEnable),
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 PcdGet32 (PcdStatusCodeValueKeyboardPresenceDetect),
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
283 if (EFI_ERROR (Status)) {
284 goto ErrorExit;
285 }
286
287 Status = InitKeyboardLayout (UsbKeyboardDevice);
288 if (EFI_ERROR (Status)) {
289 goto ErrorExit;
290 }
291
292 //
293 // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
294 // for the USB keyboard device.
295 // USB keyboard is a hot plug device, and expected to work immediately
296 // when plugging into system, other conventional console devices could
297 // distinguish it by its device path.
298 //
299 Status = gBS->InstallMultipleProtocolInterfaces (
300 &Controller,
301 &gEfiSimpleTextInProtocolGuid,
302 &UsbKeyboardDevice->SimpleInput,
303 &gEfiSimpleTextInputExProtocolGuid,
304 &UsbKeyboardDevice->SimpleInputEx,
305 NULL
306 );
307 if (EFI_ERROR (Status)) {
308 goto ErrorExit;
309 }
310
311 //
312 // Reset USB Keyboard Device exhaustively.
313 //
314 Status = UsbKeyboardDevice->SimpleInput.Reset (
315 &UsbKeyboardDevice->SimpleInput,
316 TRUE
317 );
318 if (EFI_ERROR (Status)) {
319 gBS->UninstallMultipleProtocolInterfaces (
320 Controller,
321 &gEfiSimpleTextInProtocolGuid,
322 &UsbKeyboardDevice->SimpleInput,
323 &gEfiSimpleTextInputExProtocolGuid,
324 &UsbKeyboardDevice->SimpleInputEx,
325 NULL
326 );
327 goto ErrorExit;
328 }
329
330 //
331 // Submit Asynchronous Interrupt Transfer to manage this device.
332 //
333 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
334 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
335 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
336
337 Status = UsbIo->UsbAsyncInterruptTransfer (
338 UsbIo,
339 EndpointAddr,
340 TRUE,
341 PollingInterval,
342 PacketSize,
343 KeyboardHandler,
344 UsbKeyboardDevice
345 );
346
347 if (EFI_ERROR (Status)) {
348 gBS->UninstallMultipleProtocolInterfaces (
349 Controller,
350 &gEfiSimpleTextInProtocolGuid,
351 &UsbKeyboardDevice->SimpleInput,
352 &gEfiSimpleTextInputExProtocolGuid,
353 &UsbKeyboardDevice->SimpleInputEx,
354 NULL
355 );
356 goto ErrorExit;
357 }
358
359 UsbKeyboardDevice->ControllerNameTable = NULL;
360 AddUnicodeString2 (
361 "eng",
362 gUsbKeyboardComponentName.SupportedLanguages,
363 &UsbKeyboardDevice->ControllerNameTable,
364 L"Generic Usb Keyboard",
365 TRUE
366 );
367 AddUnicodeString2 (
368 "en",
369 gUsbKeyboardComponentName2.SupportedLanguages,
370 &UsbKeyboardDevice->ControllerNameTable,
371 L"Generic Usb Keyboard",
372 FALSE
373 );
374
375 return EFI_SUCCESS;
376
377 //
378 // Error handler
379 //
380 ErrorExit:
381 if (UsbKeyboardDevice != NULL) {
382 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
383 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
384 }
385 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
386 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
387 }
388 FreePool (UsbKeyboardDevice);
389 UsbKeyboardDevice = NULL;
390 }
391 gBS->CloseProtocol (
392 Controller,
393 &gEfiUsbIoProtocolGuid,
394 This->DriverBindingHandle,
395 Controller
396 );
397 return Status;
398
399 }
400
401
402 /**
403 Stop the USB keyboard device handled by this driver.
404
405 @param This The USB keyboard driver binding protocol.
406 @param Controller The controller to release.
407 @param NumberOfChildren The number of handles in ChildHandleBuffer.
408 @param ChildHandleBuffer The array of child handle.
409
410 @retval EFI_SUCCESS The device was stopped.
411 @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
412 is not installed on Controller.
413 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
414 @retval Others Fail to uninstall protocols attached on the device.
415
416 **/
417 EFI_STATUS
418 EFIAPI
419 USBKeyboardDriverBindingStop (
420 IN EFI_DRIVER_BINDING_PROTOCOL *This,
421 IN EFI_HANDLE Controller,
422 IN UINTN NumberOfChildren,
423 IN EFI_HANDLE *ChildHandleBuffer
424 )
425 {
426 EFI_STATUS Status;
427 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
428 USB_KB_DEV *UsbKeyboardDevice;
429
430 Status = gBS->OpenProtocol (
431 Controller,
432 &gEfiSimpleTextInProtocolGuid,
433 (VOID **) &SimpleInput,
434 This->DriverBindingHandle,
435 Controller,
436 EFI_OPEN_PROTOCOL_GET_PROTOCOL
437 );
438 if (EFI_ERROR (Status)) {
439 return EFI_UNSUPPORTED;
440 }
441
442 Status = gBS->OpenProtocol (
443 Controller,
444 &gEfiSimpleTextInputExProtocolGuid,
445 NULL,
446 This->DriverBindingHandle,
447 Controller,
448 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
449 );
450 if (EFI_ERROR (Status)) {
451 return EFI_UNSUPPORTED;
452 }
453
454 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
455
456 //
457 // The key data input from this device will be disabled.
458 //
459 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
460 EFI_PROGRESS_CODE,
461 PcdGet32 (PcdStatusCodeValueKeyboardDisable),
462 UsbKeyboardDevice->DevicePath
463 );
464
465 //
466 // Delete the Asynchronous Interrupt Transfer from this device
467 //
468 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
469 UsbKeyboardDevice->UsbIo,
470 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
471 FALSE,
472 UsbKeyboardDevice->IntEndpointDescriptor.Interval,
473 0,
474 NULL,
475 NULL
476 );
477
478 gBS->CloseProtocol (
479 Controller,
480 &gEfiUsbIoProtocolGuid,
481 This->DriverBindingHandle,
482 Controller
483 );
484
485 Status = gBS->UninstallMultipleProtocolInterfaces (
486 Controller,
487 &gEfiSimpleTextInProtocolGuid,
488 &UsbKeyboardDevice->SimpleInput,
489 &gEfiSimpleTextInputExProtocolGuid,
490 &UsbKeyboardDevice->SimpleInputEx,
491 NULL
492 );
493 //
494 // Free all resources.
495 //
496 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
497 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
498 gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey);
499 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
500 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
501
502 ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
503 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
504
505 if (UsbKeyboardDevice->ControllerNameTable != NULL) {
506 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
507 }
508
509 FreePool (UsbKeyboardDevice);
510
511 return Status;
512 }
513
514 /**
515 Internal function to read the next keystroke from the keyboard buffer.
516
517 @param UsbKeyboardDevice USB keyboard's private structure.
518 @param KeyData A pointer to buffer to hold the keystroke
519 data for the key that was pressed.
520
521 @retval EFI_SUCCESS The keystroke information was returned.
522 @retval EFI_NOT_READY There was no keystroke data availiable.
523 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
524 hardware errors.
525 @retval EFI_INVALID_PARAMETER KeyData is NULL.
526 @retval Others Fail to translate keycode into EFI_INPUT_KEY
527
528 **/
529 EFI_STATUS
530 EFIAPI
531 USBKeyboardReadKeyStrokeWorker (
532 IN OUT USB_KB_DEV *UsbKeyboardDevice,
533 OUT EFI_KEY_DATA *KeyData
534 )
535 {
536 EFI_STATUS Status;
537 UINT8 KeyCode;
538 LIST_ENTRY *Link;
539 LIST_ENTRY *NotifyList;
540 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
541 EFI_KEY_DATA OriginalKeyData;
542
543 if (KeyData == NULL) {
544 return EFI_INVALID_PARAMETER;
545 }
546
547 //
548 // If there is no saved USB keycode, fetch it
549 // by calling USBKeyboardCheckForKey().
550 //
551 if (UsbKeyboardDevice->CurKeyCode == 0) {
552 Status = USBKeyboardCheckForKey (UsbKeyboardDevice);
553 if (EFI_ERROR (Status)) {
554 return EFI_NOT_READY;
555 }
556 }
557
558 KeyData->Key.UnicodeChar = 0;
559 KeyData->Key.ScanCode = SCAN_NULL;
560
561 //
562 // Store the current keycode and clear it.
563 //
564 KeyCode = UsbKeyboardDevice->CurKeyCode;
565 UsbKeyboardDevice->CurKeyCode = 0;
566
567 //
568 // Translate saved USB keycode into EFI_INPUT_KEY
569 //
570 Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData->Key);
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 //
576 // Get current state of various toggled attributes as well as input modifier values,
577 // and set them as valid.
578 //
579 CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState));
580
581 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
582 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
583
584 //
585 // Switch the control value to their original characters.
586 // In UsbKeyCodeToEfiInputKey() the CTRL-Alpha characters have been switched to
587 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A),
588 // here switch them back for notification function.
589 //
590 CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA));
591 if (UsbKeyboardDevice->CtrlOn) {
592 if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {
593 if (UsbKeyboardDevice->CapsOn) {
594 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1);
595 } else {
596 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1);
597 }
598 }
599 }
600
601 //
602 // Invoke notification functions if the key is registered.
603 //
604 NotifyList = &UsbKeyboardDevice->NotifyList;
605 for (Link = GetFirstNode (NotifyList);
606 !IsNull (NotifyList, Link);
607 Link = GetNextNode (NotifyList, Link)) {
608 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
609 if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) {
610 CurrentNotify->KeyNotificationFn (&OriginalKeyData);
611 }
612 }
613
614 return EFI_SUCCESS;
615 }
616
617 /**
618 Reset the input device and optionally run diagnostics
619
620 There are 2 types of reset for USB keyboard.
621 For non-exhaustive reset, only keyboard buffer is cleared.
622 For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
623 is also re-initialized.
624
625 @param This Protocol instance pointer.
626 @param ExtendedVerification Driver may perform diagnostics on reset.
627
628 @retval EFI_SUCCESS The device was reset.
629 @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset.
630
631 **/
632 EFI_STATUS
633 EFIAPI
634 USBKeyboardReset (
635 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
636 IN BOOLEAN ExtendedVerification
637 )
638 {
639 EFI_STATUS Status;
640 USB_KB_DEV *UsbKeyboardDevice;
641
642 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
643
644 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
645 EFI_PROGRESS_CODE,
646 PcdGet32 (PcdStatusCodeValueKeyboardReset),
647 UsbKeyboardDevice->DevicePath
648 );
649
650 //
651 // Non-exhaustive reset:
652 // only reset private data structures.
653 //
654 if (!ExtendedVerification) {
655 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
656 EFI_PROGRESS_CODE,
657 PcdGet32 (PcdStatusCodeValueKeyboardClearBuffer),
658 UsbKeyboardDevice->DevicePath
659 );
660 //
661 // Clear the key buffer of this USB keyboard
662 //
663 InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));
664 UsbKeyboardDevice->CurKeyCode = 0;
665
666 return EFI_SUCCESS;
667 }
668
669 //
670 // Exhaustive reset
671 //
672 Status = InitUSBKeyboard (UsbKeyboardDevice);
673 UsbKeyboardDevice->CurKeyCode = 0;
674 if (EFI_ERROR (Status)) {
675 return EFI_DEVICE_ERROR;
676 }
677
678 return EFI_SUCCESS;
679 }
680
681
682 /**
683 Reads the next keystroke from the input device.
684
685 @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
686 @param Key A pointer to a buffer that is filled in with the keystroke
687 information for the key that was pressed.
688
689 @retval EFI_SUCCESS The keystroke information was returned.
690 @retval EFI_NOT_READY There was no keystroke data availiable.
691 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
692 hardware errors.
693
694 **/
695 EFI_STATUS
696 EFIAPI
697 USBKeyboardReadKeyStroke (
698 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
699 OUT EFI_INPUT_KEY *Key
700 )
701 {
702 USB_KB_DEV *UsbKeyboardDevice;
703 EFI_STATUS Status;
704 EFI_KEY_DATA KeyData;
705
706 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
707
708 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
709 if (EFI_ERROR (Status)) {
710 return Status;
711 }
712
713 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
714
715 return EFI_SUCCESS;
716 }
717
718
719 /**
720 Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
721 and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
722
723 @param Event Event to be signaled when a key is pressed.
724 @param Context Points to USB_KB_DEV instance.
725
726 **/
727 VOID
728 EFIAPI
729 USBKeyboardWaitForKey (
730 IN EFI_EVENT Event,
731 IN VOID *Context
732 )
733 {
734 USB_KB_DEV *UsbKeyboardDevice;
735
736 UsbKeyboardDevice = (USB_KB_DEV *) Context;
737
738 if (UsbKeyboardDevice->CurKeyCode == 0) {
739 if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {
740 //
741 // If no pending key, simply return.
742 //
743 return ;
744 }
745 }
746 //
747 // If there is pending key, signal the event.
748 //
749 gBS->SignalEvent (Event);
750 }
751
752
753 /**
754 Check whether there is key pending in the keyboard buffer.
755
756 @param UsbKeyboardDevice The USB_KB_DEV instance.
757
758 @retval EFI_SUCCESS There is pending key to read.
759 @retval EFI_NOT_READY No pending key to read.
760
761 **/
762 EFI_STATUS
763 EFIAPI
764 USBKeyboardCheckForKey (
765 IN OUT USB_KB_DEV *UsbKeyboardDevice
766 )
767 {
768 EFI_STATUS Status;
769 UINT8 KeyCode;
770
771 //
772 // Fetch raw data from the USB keyboard buffer,
773 // and translate it into USB keycode.
774 //
775 Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
776 if (EFI_ERROR (Status)) {
777 return EFI_NOT_READY;
778 }
779
780 UsbKeyboardDevice->CurKeyCode = KeyCode;
781 return EFI_SUCCESS;
782 }
783
784 /**
785 Free keyboard notify list.
786
787 @param NotifyList The keyboard notify list to free.
788
789 @retval EFI_SUCCESS Free the notify list successfully.
790 @retval EFI_INVALID_PARAMETER NotifyList is NULL.
791
792 **/
793 EFI_STATUS
794 EFIAPI
795 KbdFreeNotifyList (
796 IN OUT LIST_ENTRY *NotifyList
797 )
798 {
799 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
800 LIST_ENTRY *Link;
801
802 if (NotifyList == NULL) {
803 return EFI_INVALID_PARAMETER;
804 }
805 while (!IsListEmpty (NotifyList)) {
806 Link = GetFirstNode (NotifyList);
807 NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
808 RemoveEntryList (Link);
809 FreePool (NotifyNode);
810 }
811
812 return EFI_SUCCESS;
813 }
814
815 /**
816 Check whether the pressed key matches a registered key or not.
817
818 @param RegsiteredData A pointer to keystroke data for the key that was registered.
819 @param InputData A pointer to keystroke data for the key that was pressed.
820
821 @retval TRUE Key pressed matches a registered key.
822 @retval FLASE Key pressed does not matches a registered key.
823
824 **/
825 BOOLEAN
826 EFIAPI
827 IsKeyRegistered (
828 IN EFI_KEY_DATA *RegsiteredData,
829 IN EFI_KEY_DATA *InputData
830 )
831 {
832 ASSERT (RegsiteredData != NULL && InputData != NULL);
833
834 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
835 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
836 return FALSE;
837 }
838
839 //
840 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
841 //
842 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
843 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
844 return FALSE;
845 }
846 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
847 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
848 return FALSE;
849 }
850
851 return TRUE;
852 }
853
854 //
855 // Simple Text Input Ex protocol functions
856 //
857 /**
858 Resets the input device hardware.
859
860 The Reset() function resets the input device hardware. As part
861 of initialization process, the firmware/device will make a quick
862 but reasonable attempt to verify that the device is functioning.
863 If the ExtendedVerification flag is TRUE the firmware may take
864 an extended amount of time to verify the device is operating on
865 reset. Otherwise the reset operation is to occur as quickly as
866 possible. The hardware verification process is not defined by
867 this specification and is left up to the platform firmware or
868 driver to implement.
869
870 @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
871
872 @param ExtendedVerification Indicates that the driver may perform a more exhaustive
873 verification operation of the device during reset.
874
875 @retval EFI_SUCCESS The device was reset.
876 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
877
878 **/
879 EFI_STATUS
880 EFIAPI
881 USBKeyboardResetEx (
882 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
883 IN BOOLEAN ExtendedVerification
884 )
885 {
886 EFI_STATUS Status;
887 USB_KB_DEV *UsbKeyboardDevice;
888 EFI_TPL OldTpl;
889
890
891 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
892
893 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
894 if (EFI_ERROR (Status)) {
895 return EFI_DEVICE_ERROR;
896 }
897
898 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
899 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
900 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
901 gBS->RestoreTPL (OldTpl);
902
903 return EFI_SUCCESS;
904
905 }
906
907 /**
908 Reads the next keystroke from the input device.
909
910 @param This Protocol instance pointer.
911 @param KeyData A pointer to a buffer that is filled in with the keystroke
912 state data for the key that was pressed.
913
914 @retval EFI_SUCCESS The keystroke information was returned.
915 @retval EFI_NOT_READY There was no keystroke data available.
916 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
917 hardware errors.
918 @retval EFI_INVALID_PARAMETER KeyData is NULL.
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 appropriately.
948 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
949 not have the setting adjusted.
950 @retval EFI_UNSUPPORTED The device does not support the ability to have its state set.
951 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
952
953 **/
954 EFI_STATUS
955 EFIAPI
956 USBKeyboardSetState (
957 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
958 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
959 )
960 {
961 USB_KB_DEV *UsbKeyboardDevice;
962
963 if (KeyToggleState == NULL) {
964 return EFI_INVALID_PARAMETER;
965 }
966
967 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
968
969 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
970 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
971 return EFI_UNSUPPORTED;
972 }
973
974 //
975 // Update the status light
976 //
977
978 UsbKeyboardDevice->ScrollOn = FALSE;
979 UsbKeyboardDevice->NumLockOn = FALSE;
980 UsbKeyboardDevice->CapsOn = FALSE;
981
982 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
983 UsbKeyboardDevice->ScrollOn = TRUE;
984 }
985 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
986 UsbKeyboardDevice->NumLockOn = TRUE;
987 }
988 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
989 UsbKeyboardDevice->CapsOn = TRUE;
990 }
991
992 SetKeyLED (UsbKeyboardDevice);
993
994 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
995
996 return EFI_SUCCESS;
997
998 }
999
1000 /**
1001 Register a notification function for a particular keystroke for the input device.
1002
1003 @param This Protocol instance pointer.
1004 @param KeyData A pointer to a buffer that is filled in with the keystroke
1005 information data for the key that was pressed.
1006 @param KeyNotificationFunction Points to the function to be called when the key
1007 sequence is typed specified by KeyData.
1008 @param NotifyHandle Points to the unique handle assigned to the registered notification.
1009
1010 @retval EFI_SUCCESS The notification function was registered successfully.
1011 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.
1012 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
1013
1014 **/
1015 EFI_STATUS
1016 EFIAPI
1017 USBKeyboardRegisterKeyNotify (
1018 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1019 IN EFI_KEY_DATA *KeyData,
1020 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
1021 OUT EFI_HANDLE *NotifyHandle
1022 )
1023 {
1024 USB_KB_DEV *UsbKeyboardDevice;
1025 EFI_STATUS Status;
1026 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1027 LIST_ENTRY *Link;
1028 LIST_ENTRY *NotifyList;
1029 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1030
1031 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1032 return EFI_INVALID_PARAMETER;
1033 }
1034
1035 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1036
1037 //
1038 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1039 //
1040 NotifyList = &UsbKeyboardDevice->NotifyList;
1041
1042 for (Link = GetFirstNode (NotifyList);
1043 !IsNull (NotifyList, Link);
1044 Link = GetNextNode (NotifyList, Link)) {
1045 CurrentNotify = CR (
1046 Link,
1047 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1048 NotifyEntry,
1049 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1050 );
1051 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1052 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1053 *NotifyHandle = CurrentNotify->NotifyHandle;
1054 return EFI_SUCCESS;
1055 }
1056 }
1057 }
1058
1059 //
1060 // Allocate resource to save the notification function
1061 //
1062 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1063 if (NewNotify == NULL) {
1064 return EFI_OUT_OF_RESOURCES;
1065 }
1066
1067 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1068 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1069 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1070 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1071
1072 //
1073 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
1074 //
1075 Status = gBS->InstallMultipleProtocolInterfaces (
1076 &NewNotify->NotifyHandle,
1077 &gSimpleTextInExNotifyGuid,
1078 NULL,
1079 NULL
1080 );
1081 ASSERT_EFI_ERROR (Status);
1082
1083 *NotifyHandle = NewNotify->NotifyHandle;
1084
1085 return EFI_SUCCESS;
1086
1087 }
1088
1089 /**
1090 Remove a registered notification function from a particular keystroke.
1091
1092 @param This Protocol instance pointer.
1093 @param NotificationHandle The handle of the notification function being unregistered.
1094
1095 @retval EFI_SUCCESS The notification function was unregistered successfully.
1096 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid
1097 @retval EFI_NOT_FOUND Cannot find the matching entry in database.
1098
1099 **/
1100 EFI_STATUS
1101 EFIAPI
1102 USBKeyboardUnregisterKeyNotify (
1103 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1104 IN EFI_HANDLE NotificationHandle
1105 )
1106 {
1107 USB_KB_DEV *UsbKeyboardDevice;
1108 EFI_STATUS Status;
1109 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1110 LIST_ENTRY *Link;
1111 LIST_ENTRY *NotifyList;
1112
1113 if (NotificationHandle == NULL) {
1114 return EFI_INVALID_PARAMETER;
1115 }
1116
1117 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1118
1119 //
1120 // Check if NotificationHandle is returned from RegisterKeyNotify().
1121 //
1122 Status = gBS->OpenProtocol (
1123 NotificationHandle,
1124 &gSimpleTextInExNotifyGuid,
1125 NULL,
1126 NULL,
1127 NULL,
1128 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1129 );
1130 if (EFI_ERROR (Status)) {
1131 return EFI_INVALID_PARAMETER;
1132 }
1133
1134 //
1135 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1136 //
1137 NotifyList = &UsbKeyboardDevice->NotifyList;
1138 for (Link = GetFirstNode (NotifyList);
1139 !IsNull (NotifyList, Link);
1140 Link = GetNextNode (NotifyList, Link)) {
1141 CurrentNotify = CR (
1142 Link,
1143 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1144 NotifyEntry,
1145 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1146 );
1147 if (CurrentNotify->NotifyHandle == NotificationHandle) {
1148 //
1149 // Remove the notification function from NotifyList and free resources
1150 //
1151 RemoveEntryList (&CurrentNotify->NotifyEntry);
1152 Status = gBS->UninstallMultipleProtocolInterfaces (
1153 CurrentNotify->NotifyHandle,
1154 &gSimpleTextInExNotifyGuid,
1155 NULL,
1156 NULL
1157 );
1158 ASSERT_EFI_ERROR (Status);
1159 FreePool (CurrentNotify);
1160 return EFI_SUCCESS;
1161 }
1162 }
1163
1164 return EFI_NOT_FOUND;
1165 }
1166