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