]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
cdd1684277e0daa6556fc36eaddd05caad49e163
[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 - 2016, 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 return EFI_NOT_READY;
611 }
612
613 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
614
615 return EFI_SUCCESS;
616 }
617
618 /**
619 Reset the input device and optionally run diagnostics
620
621 There are 2 types of reset for USB keyboard.
622 For non-exhaustive reset, only keyboard buffer is cleared.
623 For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
624 is also re-initialized.
625
626 @param This Protocol instance pointer.
627 @param ExtendedVerification Driver may perform diagnostics on reset.
628
629 @retval EFI_SUCCESS The device was reset.
630 @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset.
631
632 **/
633 EFI_STATUS
634 EFIAPI
635 USBKeyboardReset (
636 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
637 IN BOOLEAN ExtendedVerification
638 )
639 {
640 EFI_STATUS Status;
641 USB_KB_DEV *UsbKeyboardDevice;
642
643 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
644
645 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
646 EFI_PROGRESS_CODE,
647 (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
648 UsbKeyboardDevice->DevicePath
649 );
650
651 //
652 // Non-exhaustive reset:
653 // only reset private data structures.
654 //
655 if (!ExtendedVerification) {
656 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
657 EFI_PROGRESS_CODE,
658 (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
659 UsbKeyboardDevice->DevicePath
660 );
661 //
662 // Clear the key buffer of this USB keyboard
663 //
664 InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
665 InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
666 InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));
667
668 return EFI_SUCCESS;
669 }
670
671 //
672 // Exhaustive reset
673 //
674 Status = InitUSBKeyboard (UsbKeyboardDevice);
675 if (EFI_ERROR (Status)) {
676 return EFI_DEVICE_ERROR;
677 }
678
679 return EFI_SUCCESS;
680 }
681
682
683 /**
684 Reads the next keystroke from the input device.
685
686 @param This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
687 @param Key A pointer to a buffer that is filled in with the keystroke
688 information for the key that was pressed.
689
690 @retval EFI_SUCCESS The keystroke information was returned.
691 @retval EFI_NOT_READY There was no keystroke data availiable.
692 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
693 hardware errors.
694
695 **/
696 EFI_STATUS
697 EFIAPI
698 USBKeyboardReadKeyStroke (
699 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
700 OUT EFI_INPUT_KEY *Key
701 )
702 {
703 USB_KB_DEV *UsbKeyboardDevice;
704 EFI_STATUS Status;
705 EFI_KEY_DATA KeyData;
706
707 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
708
709 //
710 // Considering if the partial keystroke is enabled, there maybe a partial
711 // keystroke in the queue, so here skip the partial keystroke and get the
712 // next key from the queue
713 //
714 while (1) {
715 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
716 if (EFI_ERROR (Status)) {
717 return Status;
718 }
719 //
720 // SimpleTextIn Protocol doesn't support partial keystroke;
721 //
722 if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {
723 continue;
724 }
725 //
726 // Translate the CTRL-Alpha characters to their corresponding control value
727 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
728 //
729 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
730 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
731 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
732 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
733 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
734 }
735 }
736
737 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
738 return EFI_SUCCESS;
739 }
740 }
741
742
743 /**
744 Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
745 and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
746
747 @param Event Event to be signaled when a key is pressed.
748 @param Context Points to USB_KB_DEV instance.
749
750 **/
751 VOID
752 EFIAPI
753 USBKeyboardWaitForKey (
754 IN EFI_EVENT Event,
755 IN VOID *Context
756 )
757 {
758 USB_KB_DEV *UsbKeyboardDevice;
759 EFI_KEY_DATA KeyData;
760 EFI_TPL OldTpl;
761
762 UsbKeyboardDevice = (USB_KB_DEV *) Context;
763
764 //
765 // Enter critical section
766 //
767 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
768
769 //
770 // WaitforKey doesn't suppor the partial key.
771 // Considering if the partial keystroke is enabled, there maybe a partial
772 // keystroke in the queue, so here skip the partial keystroke and get the
773 // next key from the queue
774 //
775 while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
776 //
777 // If there is pending key, signal the event.
778 //
779 CopyMem (
780 &KeyData,
781 UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
782 sizeof (EFI_KEY_DATA)
783 );
784 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
785 Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
786 continue;
787 }
788 gBS->SignalEvent (Event);
789 break;
790 }
791 //
792 // Leave critical section and return
793 //
794 gBS->RestoreTPL (OldTpl);
795 }
796
797 /**
798 Timer handler to convert the key from USB.
799
800 @param Event Indicates the event that invoke this function.
801 @param Context Indicates the calling context.
802 **/
803 VOID
804 EFIAPI
805 USBKeyboardTimerHandler (
806 IN EFI_EVENT Event,
807 IN VOID *Context
808 )
809 {
810 EFI_STATUS Status;
811 USB_KB_DEV *UsbKeyboardDevice;
812 UINT8 KeyCode;
813 EFI_KEY_DATA KeyData;
814
815 UsbKeyboardDevice = (USB_KB_DEV *) Context;
816
817 //
818 // Fetch raw data from the USB keyboard buffer,
819 // and translate it into USB keycode.
820 //
821 Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
822 if (EFI_ERROR (Status)) {
823 return ;
824 }
825
826 //
827 // Translate saved USB keycode into EFI_INPUT_KEY
828 //
829 Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
830 if (EFI_ERROR (Status)) {
831 return ;
832 }
833
834 //
835 // Insert to the EFI Key queue
836 //
837 Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
838 }
839
840 /**
841 Free keyboard notify list.
842
843 @param NotifyList The keyboard notify list to free.
844
845 @retval EFI_SUCCESS Free the notify list successfully.
846 @retval EFI_INVALID_PARAMETER NotifyList is NULL.
847
848 **/
849 EFI_STATUS
850 KbdFreeNotifyList (
851 IN OUT LIST_ENTRY *NotifyList
852 )
853 {
854 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
855 LIST_ENTRY *Link;
856
857 if (NotifyList == NULL) {
858 return EFI_INVALID_PARAMETER;
859 }
860 while (!IsListEmpty (NotifyList)) {
861 Link = GetFirstNode (NotifyList);
862 NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
863 RemoveEntryList (Link);
864 FreePool (NotifyNode);
865 }
866
867 return EFI_SUCCESS;
868 }
869
870 /**
871 Check whether the pressed key matches a registered key or not.
872
873 @param RegsiteredData A pointer to keystroke data for the key that was registered.
874 @param InputData A pointer to keystroke data for the key that was pressed.
875
876 @retval TRUE Key pressed matches a registered key.
877 @retval FLASE Key pressed does not matches a registered key.
878
879 **/
880 BOOLEAN
881 IsKeyRegistered (
882 IN EFI_KEY_DATA *RegsiteredData,
883 IN EFI_KEY_DATA *InputData
884 )
885 {
886 ASSERT (RegsiteredData != NULL && InputData != NULL);
887
888 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
889 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
890 return FALSE;
891 }
892
893 //
894 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
895 //
896 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
897 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
898 return FALSE;
899 }
900 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
901 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
902 return FALSE;
903 }
904
905 return TRUE;
906 }
907
908 //
909 // Simple Text Input Ex protocol functions
910 //
911 /**
912 Resets the input device hardware.
913
914 The Reset() function resets the input device hardware. As part
915 of initialization process, the firmware/device will make a quick
916 but reasonable attempt to verify that the device is functioning.
917 If the ExtendedVerification flag is TRUE the firmware may take
918 an extended amount of time to verify the device is operating on
919 reset. Otherwise the reset operation is to occur as quickly as
920 possible. The hardware verification process is not defined by
921 this specification and is left up to the platform firmware or
922 driver to implement.
923
924 @param This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
925
926 @param ExtendedVerification Indicates that the driver may perform a more exhaustive
927 verification operation of the device during reset.
928
929 @retval EFI_SUCCESS The device was reset.
930 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could not be reset.
931
932 **/
933 EFI_STATUS
934 EFIAPI
935 USBKeyboardResetEx (
936 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
937 IN BOOLEAN ExtendedVerification
938 )
939 {
940 EFI_STATUS Status;
941 USB_KB_DEV *UsbKeyboardDevice;
942
943 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
944
945 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
946 if (EFI_ERROR (Status)) {
947 return EFI_DEVICE_ERROR;
948 }
949
950 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
951 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
952
953 return EFI_SUCCESS;
954
955 }
956
957 /**
958 Reads the next keystroke from the input device.
959
960 @param This Protocol instance pointer.
961 @param KeyData A pointer to a buffer that is filled in with the keystroke
962 state data for the key that was pressed.
963
964 @retval EFI_SUCCESS The keystroke information was returned.
965 @retval EFI_NOT_READY There was no keystroke data available.
966 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
967 hardware errors.
968 @retval EFI_INVALID_PARAMETER KeyData is NULL.
969
970 **/
971 EFI_STATUS
972 EFIAPI
973 USBKeyboardReadKeyStrokeEx (
974 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
975 OUT EFI_KEY_DATA *KeyData
976 )
977 {
978 USB_KB_DEV *UsbKeyboardDevice;
979
980 if (KeyData == NULL) {
981 return EFI_INVALID_PARAMETER;
982 }
983
984 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
985
986 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
987
988 }
989
990 /**
991 Set certain state for the input device.
992
993 @param This Protocol instance pointer.
994 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
995 state for the input device.
996
997 @retval EFI_SUCCESS The device state was set appropriately.
998 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
999 not have the setting adjusted.
1000 @retval EFI_UNSUPPORTED The device does not support the ability to have its state set.
1001 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
1002
1003 **/
1004 EFI_STATUS
1005 EFIAPI
1006 USBKeyboardSetState (
1007 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1008 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
1009 )
1010 {
1011 USB_KB_DEV *UsbKeyboardDevice;
1012
1013 if (KeyToggleState == NULL) {
1014 return EFI_INVALID_PARAMETER;
1015 }
1016
1017 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1018
1019 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
1020 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
1021 return EFI_UNSUPPORTED;
1022 }
1023
1024 //
1025 // Update the status light
1026 //
1027
1028 UsbKeyboardDevice->ScrollOn = FALSE;
1029 UsbKeyboardDevice->NumLockOn = FALSE;
1030 UsbKeyboardDevice->CapsOn = FALSE;
1031 UsbKeyboardDevice->IsSupportPartialKey = FALSE;
1032
1033 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
1034 UsbKeyboardDevice->ScrollOn = TRUE;
1035 }
1036 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
1037 UsbKeyboardDevice->NumLockOn = TRUE;
1038 }
1039 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
1040 UsbKeyboardDevice->CapsOn = TRUE;
1041 }
1042 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
1043 UsbKeyboardDevice->IsSupportPartialKey = TRUE;
1044 }
1045
1046 SetKeyLED (UsbKeyboardDevice);
1047
1048 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
1049
1050 return EFI_SUCCESS;
1051
1052 }
1053
1054 /**
1055 Register a notification function for a particular keystroke for the input device.
1056
1057 @param This Protocol instance pointer.
1058 @param KeyData A pointer to a buffer that is filled in with the keystroke
1059 information data for the key that was pressed.
1060 @param KeyNotificationFunction Points to the function to be called when the key
1061 sequence is typed specified by KeyData.
1062 @param NotifyHandle Points to the unique handle assigned to the registered notification.
1063
1064 @retval EFI_SUCCESS The notification function was registered successfully.
1065 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.
1066 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
1067
1068 **/
1069 EFI_STATUS
1070 EFIAPI
1071 USBKeyboardRegisterKeyNotify (
1072 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1073 IN EFI_KEY_DATA *KeyData,
1074 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
1075 OUT VOID **NotifyHandle
1076 )
1077 {
1078 USB_KB_DEV *UsbKeyboardDevice;
1079 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1080 LIST_ENTRY *Link;
1081 LIST_ENTRY *NotifyList;
1082 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1083
1084 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1085 return EFI_INVALID_PARAMETER;
1086 }
1087
1088 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1089
1090 //
1091 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1092 //
1093 NotifyList = &UsbKeyboardDevice->NotifyList;
1094
1095 for (Link = GetFirstNode (NotifyList);
1096 !IsNull (NotifyList, Link);
1097 Link = GetNextNode (NotifyList, Link)) {
1098 CurrentNotify = CR (
1099 Link,
1100 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1101 NotifyEntry,
1102 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1103 );
1104 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1105 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1106 *NotifyHandle = CurrentNotify;
1107 return EFI_SUCCESS;
1108 }
1109 }
1110 }
1111
1112 //
1113 // Allocate resource to save the notification function
1114 //
1115 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1116 if (NewNotify == NULL) {
1117 return EFI_OUT_OF_RESOURCES;
1118 }
1119
1120 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1121 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1122 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1123 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1124
1125
1126 *NotifyHandle = NewNotify;
1127
1128 return EFI_SUCCESS;
1129
1130 }
1131
1132 /**
1133 Remove a registered notification function from a particular keystroke.
1134
1135 @param This Protocol instance pointer.
1136 @param NotificationHandle The handle of the notification function being unregistered.
1137
1138 @retval EFI_SUCCESS The notification function was unregistered successfully.
1139 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid
1140
1141 **/
1142 EFI_STATUS
1143 EFIAPI
1144 USBKeyboardUnregisterKeyNotify (
1145 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1146 IN VOID *NotificationHandle
1147 )
1148 {
1149 USB_KB_DEV *UsbKeyboardDevice;
1150 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1151 LIST_ENTRY *Link;
1152 LIST_ENTRY *NotifyList;
1153
1154 if (NotificationHandle == NULL) {
1155 return EFI_INVALID_PARAMETER;
1156 }
1157
1158 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1159
1160 //
1161 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1162 //
1163 NotifyList = &UsbKeyboardDevice->NotifyList;
1164 for (Link = GetFirstNode (NotifyList);
1165 !IsNull (NotifyList, Link);
1166 Link = GetNextNode (NotifyList, Link)) {
1167 CurrentNotify = CR (
1168 Link,
1169 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1170 NotifyEntry,
1171 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1172 );
1173 if (CurrentNotify == NotificationHandle) {
1174 //
1175 // Remove the notification function from NotifyList and free resources
1176 //
1177 RemoveEntryList (&CurrentNotify->NotifyEntry);
1178
1179 FreePool (CurrentNotify);
1180 return EFI_SUCCESS;
1181 }
1182 }
1183
1184 //
1185 // Cannot find the matching entry in database.
1186 //
1187 return EFI_INVALID_PARAMETER;
1188 }
1189
1190 /**
1191 Process key notify.
1192
1193 @param Event Indicates the event that invoke this function.
1194 @param Context Indicates the calling context.
1195 **/
1196 VOID
1197 EFIAPI
1198 KeyNotifyProcessHandler (
1199 IN EFI_EVENT Event,
1200 IN VOID *Context
1201 )
1202 {
1203 EFI_STATUS Status;
1204 USB_KB_DEV *UsbKeyboardDevice;
1205 EFI_KEY_DATA KeyData;
1206 LIST_ENTRY *Link;
1207 LIST_ENTRY *NotifyList;
1208 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1209 EFI_TPL OldTpl;
1210
1211 UsbKeyboardDevice = (USB_KB_DEV *) Context;
1212
1213 //
1214 // Invoke notification functions.
1215 //
1216 NotifyList = &UsbKeyboardDevice->NotifyList;
1217 while (TRUE) {
1218 //
1219 // Enter critical section
1220 //
1221 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1222 Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));
1223 //
1224 // Leave critical section
1225 //
1226 gBS->RestoreTPL (OldTpl);
1227 if (EFI_ERROR (Status)) {
1228 break;
1229 }
1230 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
1231 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
1232 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1233 CurrentNotify->KeyNotificationFn (&KeyData);
1234 }
1235 }
1236 }
1237 }
1238