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