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