]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
Minor refinement for USB modules.
[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, so a HotPlugDeviceGuid is installed onto
297 // the usb keyboard device handle, to distinguish it from other conventional
298 // console devices.
299 //
300 Status = gBS->InstallMultipleProtocolInterfaces (
301 &Controller,
302 &gEfiSimpleTextInProtocolGuid,
303 &UsbKeyboardDevice->SimpleInput,
304 &gEfiSimpleTextInputExProtocolGuid,
305 &UsbKeyboardDevice->SimpleInputEx,
306 &gEfiHotPlugDeviceGuid,
307 NULL,
308 NULL
309 );
310 if (EFI_ERROR (Status)) {
311 goto ErrorExit;
312 }
313
314 //
315 // Reset USB Keyboard Device exhaustively.
316 //
317 Status = UsbKeyboardDevice->SimpleInput.Reset (
318 &UsbKeyboardDevice->SimpleInput,
319 TRUE
320 );
321 if (EFI_ERROR (Status)) {
322 gBS->UninstallMultipleProtocolInterfaces (
323 Controller,
324 &gEfiSimpleTextInProtocolGuid,
325 &UsbKeyboardDevice->SimpleInput,
326 &gEfiSimpleTextInputExProtocolGuid,
327 &UsbKeyboardDevice->SimpleInputEx,
328 &gEfiHotPlugDeviceGuid,
329 NULL,
330 NULL
331 );
332 goto ErrorExit;
333 }
334
335 //
336 // Submit Asynchronous Interrupt Transfer to manage this device.
337 //
338 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
339 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
340 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
341
342 Status = UsbIo->UsbAsyncInterruptTransfer (
343 UsbIo,
344 EndpointAddr,
345 TRUE,
346 PollingInterval,
347 PacketSize,
348 KeyboardHandler,
349 UsbKeyboardDevice
350 );
351
352 if (EFI_ERROR (Status)) {
353 gBS->UninstallMultipleProtocolInterfaces (
354 Controller,
355 &gEfiSimpleTextInProtocolGuid,
356 &UsbKeyboardDevice->SimpleInput,
357 &gEfiSimpleTextInputExProtocolGuid,
358 &UsbKeyboardDevice->SimpleInputEx,
359 &gEfiHotPlugDeviceGuid,
360 NULL,
361 NULL
362 );
363 goto ErrorExit;
364 }
365
366 UsbKeyboardDevice->ControllerNameTable = NULL;
367 AddUnicodeString2 (
368 "eng",
369 gUsbKeyboardComponentName.SupportedLanguages,
370 &UsbKeyboardDevice->ControllerNameTable,
371 L"Generic Usb Keyboard",
372 TRUE
373 );
374 AddUnicodeString2 (
375 "en",
376 gUsbKeyboardComponentName2.SupportedLanguages,
377 &UsbKeyboardDevice->ControllerNameTable,
378 L"Generic Usb Keyboard",
379 FALSE
380 );
381
382 return EFI_SUCCESS;
383
384 //
385 // Error handler
386 //
387 ErrorExit:
388 if (UsbKeyboardDevice != NULL) {
389 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
390 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
391 }
392 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
393 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
394 }
395 FreePool (UsbKeyboardDevice);
396 UsbKeyboardDevice = NULL;
397 }
398 gBS->CloseProtocol (
399 Controller,
400 &gEfiUsbIoProtocolGuid,
401 This->DriverBindingHandle,
402 Controller
403 );
404 return Status;
405
406 }
407
408
409 /**
410 Stop the USB keyboard device handled by this driver.
411
412 @param This The USB keyboard driver binding protocol.
413 @param Controller The controller to release.
414 @param NumberOfChildren The number of handles in ChildHandleBuffer.
415 @param ChildHandleBuffer The array of child handle.
416
417 @retval EFI_SUCCESS The device was stopped.
418 @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
419 is not installed on Controller.
420 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
421 @retval Others Fail to uninstall protocols attached on the device.
422
423 **/
424 EFI_STATUS
425 EFIAPI
426 USBKeyboardDriverBindingStop (
427 IN EFI_DRIVER_BINDING_PROTOCOL *This,
428 IN EFI_HANDLE Controller,
429 IN UINTN NumberOfChildren,
430 IN EFI_HANDLE *ChildHandleBuffer
431 )
432 {
433 EFI_STATUS Status;
434 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
435 USB_KB_DEV *UsbKeyboardDevice;
436
437 Status = gBS->OpenProtocol (
438 Controller,
439 &gEfiSimpleTextInProtocolGuid,
440 (VOID **) &SimpleInput,
441 This->DriverBindingHandle,
442 Controller,
443 EFI_OPEN_PROTOCOL_GET_PROTOCOL
444 );
445 if (EFI_ERROR (Status)) {
446 return EFI_UNSUPPORTED;
447 }
448
449 Status = gBS->OpenProtocol (
450 Controller,
451 &gEfiSimpleTextInputExProtocolGuid,
452 NULL,
453 This->DriverBindingHandle,
454 Controller,
455 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
456 );
457 if (EFI_ERROR (Status)) {
458 return EFI_UNSUPPORTED;
459 }
460
461 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
462
463 //
464 // The key data input from this device will be disabled.
465 //
466 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
467 EFI_PROGRESS_CODE,
468 PcdGet32 (PcdStatusCodeValueKeyboardDisable),
469 UsbKeyboardDevice->DevicePath
470 );
471
472 //
473 // Delete the Asynchronous Interrupt Transfer from this device
474 //
475 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
476 UsbKeyboardDevice->UsbIo,
477 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
478 FALSE,
479 UsbKeyboardDevice->IntEndpointDescriptor.Interval,
480 0,
481 NULL,
482 NULL
483 );
484
485 gBS->CloseProtocol (
486 Controller,
487 &gEfiUsbIoProtocolGuid,
488 This->DriverBindingHandle,
489 Controller
490 );
491
492 Status = gBS->UninstallMultipleProtocolInterfaces (
493 Controller,
494 &gEfiSimpleTextInProtocolGuid,
495 &UsbKeyboardDevice->SimpleInput,
496 &gEfiSimpleTextInputExProtocolGuid,
497 &UsbKeyboardDevice->SimpleInputEx,
498 &gEfiHotPlugDeviceGuid,
499 NULL,
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 EFI_STATUS Status;
1035 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1036 LIST_ENTRY *Link;
1037 LIST_ENTRY *NotifyList;
1038 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1039
1040 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1041 return EFI_INVALID_PARAMETER;
1042 }
1043
1044 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1045
1046 //
1047 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1048 //
1049 NotifyList = &UsbKeyboardDevice->NotifyList;
1050
1051 for (Link = GetFirstNode (NotifyList);
1052 !IsNull (NotifyList, Link);
1053 Link = GetNextNode (NotifyList, Link)) {
1054 CurrentNotify = CR (
1055 Link,
1056 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1057 NotifyEntry,
1058 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1059 );
1060 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1061 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1062 *NotifyHandle = CurrentNotify->NotifyHandle;
1063 return EFI_SUCCESS;
1064 }
1065 }
1066 }
1067
1068 //
1069 // Allocate resource to save the notification function
1070 //
1071 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1072 if (NewNotify == NULL) {
1073 return EFI_OUT_OF_RESOURCES;
1074 }
1075
1076 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1077 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1078 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1079 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1080
1081 //
1082 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
1083 //
1084 Status = gBS->InstallMultipleProtocolInterfaces (
1085 &NewNotify->NotifyHandle,
1086 &gSimpleTextInExNotifyGuid,
1087 NULL,
1088 NULL
1089 );
1090 ASSERT_EFI_ERROR (Status);
1091
1092 *NotifyHandle = NewNotify->NotifyHandle;
1093
1094 return EFI_SUCCESS;
1095
1096 }
1097
1098 /**
1099 Remove a registered notification function from a particular keystroke.
1100
1101 @param This Protocol instance pointer.
1102 @param NotificationHandle The handle of the notification function being unregistered.
1103
1104 @retval EFI_SUCCESS The notification function was unregistered successfully.
1105 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid
1106 @retval EFI_NOT_FOUND Cannot find the matching entry in database.
1107
1108 **/
1109 EFI_STATUS
1110 EFIAPI
1111 USBKeyboardUnregisterKeyNotify (
1112 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1113 IN EFI_HANDLE NotificationHandle
1114 )
1115 {
1116 USB_KB_DEV *UsbKeyboardDevice;
1117 EFI_STATUS Status;
1118 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1119 LIST_ENTRY *Link;
1120 LIST_ENTRY *NotifyList;
1121
1122 if (NotificationHandle == NULL) {
1123 return EFI_INVALID_PARAMETER;
1124 }
1125
1126 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1127
1128 //
1129 // Check if NotificationHandle is returned from RegisterKeyNotify().
1130 //
1131 Status = gBS->OpenProtocol (
1132 NotificationHandle,
1133 &gSimpleTextInExNotifyGuid,
1134 NULL,
1135 NULL,
1136 NULL,
1137 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1138 );
1139 if (EFI_ERROR (Status)) {
1140 return EFI_INVALID_PARAMETER;
1141 }
1142
1143 //
1144 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1145 //
1146 NotifyList = &UsbKeyboardDevice->NotifyList;
1147 for (Link = GetFirstNode (NotifyList);
1148 !IsNull (NotifyList, Link);
1149 Link = GetNextNode (NotifyList, Link)) {
1150 CurrentNotify = CR (
1151 Link,
1152 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1153 NotifyEntry,
1154 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1155 );
1156 if (CurrentNotify->NotifyHandle == NotificationHandle) {
1157 //
1158 // Remove the notification function from NotifyList and free resources
1159 //
1160 RemoveEntryList (&CurrentNotify->NotifyEntry);
1161 Status = gBS->UninstallMultipleProtocolInterfaces (
1162 CurrentNotify->NotifyHandle,
1163 &gSimpleTextInExNotifyGuid,
1164 NULL,
1165 NULL
1166 );
1167 ASSERT_EFI_ERROR (Status);
1168 FreePool (CurrentNotify);
1169 return EFI_SUCCESS;
1170 }
1171 }
1172
1173 return EFI_NOT_FOUND;
1174 }
1175