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