]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
fb2bf3fd814de47f3d2e719ed5326d9152d140d2
[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 - 2017, 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
1059 the keystroke information for the key that was
1060 pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
1061 and KeyData.KeyState.KeyShiftState are 0, then any incomplete
1062 keystroke will trigger a notification of the KeyNotificationFunction.
1063 @param KeyNotificationFunction Points to the function to be called when the key
1064 sequence is typed specified by KeyData. This notification function
1065 should be called at <=TPL_CALLBACK.
1066 @param NotifyHandle Points to the unique handle assigned to the registered notification.
1067
1068 @retval EFI_SUCCESS The notification function was registered successfully.
1069 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.
1070 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
1071
1072 **/
1073 EFI_STATUS
1074 EFIAPI
1075 USBKeyboardRegisterKeyNotify (
1076 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1077 IN EFI_KEY_DATA *KeyData,
1078 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
1079 OUT VOID **NotifyHandle
1080 )
1081 {
1082 USB_KB_DEV *UsbKeyboardDevice;
1083 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1084 LIST_ENTRY *Link;
1085 LIST_ENTRY *NotifyList;
1086 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1087
1088 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1089 return EFI_INVALID_PARAMETER;
1090 }
1091
1092 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1093
1094 //
1095 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1096 //
1097 NotifyList = &UsbKeyboardDevice->NotifyList;
1098
1099 for (Link = GetFirstNode (NotifyList);
1100 !IsNull (NotifyList, Link);
1101 Link = GetNextNode (NotifyList, Link)) {
1102 CurrentNotify = CR (
1103 Link,
1104 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1105 NotifyEntry,
1106 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1107 );
1108 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1109 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1110 *NotifyHandle = CurrentNotify;
1111 return EFI_SUCCESS;
1112 }
1113 }
1114 }
1115
1116 //
1117 // Allocate resource to save the notification function
1118 //
1119 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1120 if (NewNotify == NULL) {
1121 return EFI_OUT_OF_RESOURCES;
1122 }
1123
1124 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1125 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1126 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1127 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1128
1129
1130 *NotifyHandle = NewNotify;
1131
1132 return EFI_SUCCESS;
1133
1134 }
1135
1136 /**
1137 Remove a registered notification function from a particular keystroke.
1138
1139 @param This Protocol instance pointer.
1140 @param NotificationHandle The handle of the notification function being unregistered.
1141
1142 @retval EFI_SUCCESS The notification function was unregistered successfully.
1143 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid
1144
1145 **/
1146 EFI_STATUS
1147 EFIAPI
1148 USBKeyboardUnregisterKeyNotify (
1149 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1150 IN VOID *NotificationHandle
1151 )
1152 {
1153 USB_KB_DEV *UsbKeyboardDevice;
1154 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1155 LIST_ENTRY *Link;
1156 LIST_ENTRY *NotifyList;
1157
1158 if (NotificationHandle == NULL) {
1159 return EFI_INVALID_PARAMETER;
1160 }
1161
1162 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1163
1164 //
1165 // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
1166 //
1167 NotifyList = &UsbKeyboardDevice->NotifyList;
1168 for (Link = GetFirstNode (NotifyList);
1169 !IsNull (NotifyList, Link);
1170 Link = GetNextNode (NotifyList, Link)) {
1171 CurrentNotify = CR (
1172 Link,
1173 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1174 NotifyEntry,
1175 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1176 );
1177 if (CurrentNotify == NotificationHandle) {
1178 //
1179 // Remove the notification function from NotifyList and free resources
1180 //
1181 RemoveEntryList (&CurrentNotify->NotifyEntry);
1182
1183 FreePool (CurrentNotify);
1184 return EFI_SUCCESS;
1185 }
1186 }
1187
1188 //
1189 // Cannot find the matching entry in database.
1190 //
1191 return EFI_INVALID_PARAMETER;
1192 }
1193
1194 /**
1195 Process key notify.
1196
1197 @param Event Indicates the event that invoke this function.
1198 @param Context Indicates the calling context.
1199 **/
1200 VOID
1201 EFIAPI
1202 KeyNotifyProcessHandler (
1203 IN EFI_EVENT Event,
1204 IN VOID *Context
1205 )
1206 {
1207 EFI_STATUS Status;
1208 USB_KB_DEV *UsbKeyboardDevice;
1209 EFI_KEY_DATA KeyData;
1210 LIST_ENTRY *Link;
1211 LIST_ENTRY *NotifyList;
1212 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1213 EFI_TPL OldTpl;
1214
1215 UsbKeyboardDevice = (USB_KB_DEV *) Context;
1216
1217 //
1218 // Invoke notification functions.
1219 //
1220 NotifyList = &UsbKeyboardDevice->NotifyList;
1221 while (TRUE) {
1222 //
1223 // Enter critical section
1224 //
1225 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1226 Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));
1227 //
1228 // Leave critical section
1229 //
1230 gBS->RestoreTPL (OldTpl);
1231 if (EFI_ERROR (Status)) {
1232 break;
1233 }
1234 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
1235 CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
1236 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1237 CurrentNotify->KeyNotificationFn (&KeyData);
1238 }
1239 }
1240 }
1241 }
1242