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