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