]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c
Merged in the following trackers from EDK:
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / efikey.c
1 /** @file
2
3 Copyright (c) 2004 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 EfiKey.c
15
16 Abstract:
17
18 USB Keyboard Driver
19
20 Revision History
21
22
23 **/
24
25 #include "efikey.h"
26 #include "keyboard.h"
27
28 //
29 // Prototypes
30 // Driver model protocol interface
31 //
32 EFI_STATUS
33 EFIAPI
34 USBKeyboardDriverBindingEntryPoint (
35 IN EFI_HANDLE ImageHandle,
36 IN EFI_SYSTEM_TABLE *SystemTable
37 );
38
39 EFI_STATUS
40 EFIAPI
41 USBKeyboardDriverBindingSupported (
42 IN EFI_DRIVER_BINDING_PROTOCOL *This,
43 IN EFI_HANDLE Controller,
44 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
45 );
46
47 EFI_STATUS
48 EFIAPI
49 USBKeyboardDriverBindingStart (
50 IN EFI_DRIVER_BINDING_PROTOCOL *This,
51 IN EFI_HANDLE Controller,
52 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
53 );
54
55 EFI_STATUS
56 EFIAPI
57 USBKeyboardDriverBindingStop (
58 IN EFI_DRIVER_BINDING_PROTOCOL *This,
59 IN EFI_HANDLE Controller,
60 IN UINTN NumberOfChildren,
61 IN EFI_HANDLE *ChildHandleBuffer
62 );
63
64 //
65 // Simple Text In Protocol Interface
66 //
67 STATIC
68 EFI_STATUS
69 EFIAPI
70 USBKeyboardReset (
71 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
72 IN BOOLEAN ExtendedVerification
73 );
74
75 STATIC
76 EFI_STATUS
77 EFIAPI
78 USBKeyboardReadKeyStroke (
79 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
80 OUT EFI_INPUT_KEY *Key
81 );
82
83 STATIC
84 VOID
85 EFIAPI
86 USBKeyboardWaitForKey (
87 IN EFI_EVENT Event,
88 IN VOID *Context
89 );
90
91 //
92 // Helper functions
93 //
94 STATIC
95 EFI_STATUS
96 USBKeyboardCheckForKey (
97 IN USB_KB_DEV *UsbKeyboardDevice
98 );
99
100 EFI_GUID gEfiUsbKeyboardDriverGuid = {
101 0xa05f5f78, 0xfb3, 0x4d10, {0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c}
102 };
103 STATIC
104 EFI_STATUS
105 KbdFreeNotifyList (
106 IN OUT LIST_ENTRY *ListHead
107 );
108 STATIC
109 BOOLEAN
110 IsKeyRegistered (
111 IN EFI_KEY_DATA *RegsiteredData,
112 IN EFI_KEY_DATA *InputData
113 );
114
115
116 //
117 // USB Keyboard Driver Global Variables
118 //
119 EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
120 USBKeyboardDriverBindingSupported,
121 USBKeyboardDriverBindingStart,
122 USBKeyboardDriverBindingStop,
123 0xa,
124 NULL,
125 NULL
126 };
127
128 EFI_STATUS
129 EFIAPI
130 USBKeyboardDriverBindingEntryPoint (
131 IN EFI_HANDLE ImageHandle,
132 IN EFI_SYSTEM_TABLE *SystemTable
133 )
134 /*++
135
136 Routine Description:
137 Driver Entry Point.
138
139 Arguments:
140 ImageHandle - EFI_HANDLE
141 SystemTable - EFI_SYSTEM_TABLE
142 Returns:
143 EFI_STATUS
144
145 --*/
146 {
147 return EfiLibInstallDriverBindingComponentName2 (
148 ImageHandle,
149 SystemTable,
150 &gUsbKeyboardDriverBinding,
151 ImageHandle,
152 &gUsbKeyboardComponentName,
153 &gUsbKeyboardComponentName2
154 );
155 }
156
157
158
159 /**
160 Supported.
161
162 @param This EFI_DRIVER_BINDING_PROTOCOL
163 @param Controller Controller handle
164 @param RemainingDevicePath EFI_DEVICE_PATH_PROTOCOL
165 EFI_STATUS
166
167 **/
168 EFI_STATUS
169 EFIAPI
170 USBKeyboardDriverBindingSupported (
171 IN EFI_DRIVER_BINDING_PROTOCOL *This,
172 IN EFI_HANDLE Controller,
173 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
174 )
175 {
176 EFI_STATUS OpenStatus;
177 EFI_USB_IO_PROTOCOL *UsbIo;
178 EFI_STATUS Status;
179
180 //
181 // Check if USB_IO protocol is attached on the controller handle.
182 //
183 OpenStatus = gBS->OpenProtocol (
184 Controller,
185 &gEfiUsbIoProtocolGuid,
186 (VOID **) &UsbIo,
187 This->DriverBindingHandle,
188 Controller,
189 EFI_OPEN_PROTOCOL_BY_DRIVER
190 );
191 if (EFI_ERROR (OpenStatus)) {
192 return OpenStatus;
193 }
194
195 //
196 // Use the USB I/O protocol interface to check whether the Controller is
197 // the Keyboard controller that can be managed by this driver.
198 //
199 Status = EFI_SUCCESS;
200
201 if (!IsUSBKeyboard (UsbIo)) {
202 Status = EFI_UNSUPPORTED;
203 }
204
205 gBS->CloseProtocol (
206 Controller,
207 &gEfiUsbIoProtocolGuid,
208 This->DriverBindingHandle,
209 Controller
210 );
211
212 return Status;
213 }
214
215
216 /**
217 Start.
218
219 @param This EFI_DRIVER_BINDING_PROTOCOL
220 @param Controller Controller handle
221 @param RemainingDevicePath EFI_DEVICE_PATH_PROTOCOL
222
223 @retval EFI_SUCCESS Success
224 @retval EFI_OUT_OF_RESOURCES Can't allocate memory
225 @retval EFI_UNSUPPORTED The Start routine fail
226
227 **/
228 EFI_STATUS
229 EFIAPI
230 USBKeyboardDriverBindingStart (
231 IN EFI_DRIVER_BINDING_PROTOCOL *This,
232 IN EFI_HANDLE Controller,
233 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
234 )
235 {
236 EFI_STATUS Status;
237 EFI_USB_IO_PROTOCOL *UsbIo;
238 USB_KB_DEV *UsbKeyboardDevice;
239 UINT8 EndpointNumber;
240 EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
241 UINT8 Index;
242 UINT8 EndpointAddr;
243 UINT8 PollingInterval;
244 UINT8 PacketSize;
245 BOOLEAN Found;
246
247 UsbKeyboardDevice = NULL;
248 Found = FALSE;
249
250 //
251 // Open USB_IO Protocol
252 //
253 Status = gBS->OpenProtocol (
254 Controller,
255 &gEfiUsbIoProtocolGuid,
256 (VOID **) &UsbIo,
257 This->DriverBindingHandle,
258 Controller,
259 EFI_OPEN_PROTOCOL_BY_DRIVER
260 );
261 if (EFI_ERROR (Status)) {
262 return Status;
263 }
264
265 UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));
266 if (UsbKeyboardDevice == NULL) {
267 gBS->CloseProtocol (
268 Controller,
269 &gEfiUsbIoProtocolGuid,
270 This->DriverBindingHandle,
271 Controller
272 );
273 return EFI_OUT_OF_RESOURCES;
274 }
275 //
276 // Get the Device Path Protocol on Controller's handle
277 //
278 Status = gBS->OpenProtocol (
279 Controller,
280 &gEfiDevicePathProtocolGuid,
281 (VOID **) &UsbKeyboardDevice->DevicePath,
282 This->DriverBindingHandle,
283 Controller,
284 EFI_OPEN_PROTOCOL_GET_PROTOCOL
285 );
286
287 if (EFI_ERROR (Status)) {
288 gBS->FreePool (UsbKeyboardDevice);
289 gBS->CloseProtocol (
290 Controller,
291 &gEfiUsbIoProtocolGuid,
292 This->DriverBindingHandle,
293 Controller
294 );
295 return Status;
296 }
297 //
298 // Report that the usb keyboard is being enabled
299 //
300 KbdReportStatusCode (
301 UsbKeyboardDevice->DevicePath,
302 EFI_PROGRESS_CODE,
303 PcdGet32 (PcdStatusCodeValueKeyboardEnable)
304 );
305
306 //
307 // This is pretty close to keyboard detection, so log progress
308 //
309 KbdReportStatusCode (
310 UsbKeyboardDevice->DevicePath,
311 EFI_PROGRESS_CODE,
312 PcdGet32 (PcdStatusCodeValueKeyboardPresenceDetect)
313 );
314
315 //
316 // Initialize UsbKeyboardDevice
317 //
318 UsbKeyboardDevice->UsbIo = UsbIo;
319
320 //
321 // Get interface & endpoint descriptor
322 //
323 UsbIo->UsbGetInterfaceDescriptor (
324 UsbIo,
325 &UsbKeyboardDevice->InterfaceDescriptor
326 );
327
328 EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;
329
330 for (Index = 0; Index < EndpointNumber; Index++) {
331
332 UsbIo->UsbGetEndpointDescriptor (
333 UsbIo,
334 Index,
335 &EndpointDescriptor
336 );
337
338 if ((EndpointDescriptor.Attributes & 0x03) == 0x03) {
339 //
340 // We only care interrupt endpoint here
341 //
342 CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
343 Found = TRUE;
344 }
345 }
346
347 if (!Found) {
348 //
349 // No interrupt endpoint found, then return unsupported.
350 //
351 gBS->FreePool (UsbKeyboardDevice);
352 gBS->CloseProtocol (
353 Controller,
354 &gEfiUsbIoProtocolGuid,
355 This->DriverBindingHandle,
356 Controller
357 );
358 return EFI_UNSUPPORTED;
359 }
360
361 UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE;
362 UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset;
363 UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke;
364
365 UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx;
366 UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx;
367 UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState;
368 UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify;
369 UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;
370
371 InitializeListHead (&UsbKeyboardDevice->NotifyList);
372
373 Status = gBS->CreateEvent (
374 EVT_NOTIFY_WAIT,
375 TPL_NOTIFY,
376 USBKeyboardWaitForKey,
377 UsbKeyboardDevice,
378 &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)
379 );
380
381 if (EFI_ERROR (Status)) {
382 goto ErrorExit;
383 }
384
385 Status = InitKeyboardLayout (UsbKeyboardDevice);
386 if (EFI_ERROR (Status)) {
387 goto ErrorExit;
388 }
389
390 Status = gBS->CreateEvent (
391 EVT_NOTIFY_WAIT,
392 TPL_NOTIFY,
393 USBKeyboardWaitForKey,
394 UsbKeyboardDevice,
395 &(UsbKeyboardDevice->SimpleInput.WaitForKey)
396 );
397
398 if (EFI_ERROR (Status)) {
399 gBS->FreePool (UsbKeyboardDevice);
400 gBS->CloseProtocol (
401 Controller,
402 &gEfiUsbIoProtocolGuid,
403 This->DriverBindingHandle,
404 Controller
405 );
406 return Status;
407 }
408
409 //
410 // Install simple txt in protocol interface
411 // for the usb keyboard device.
412 // Usb keyboard is a hot plug device, and expected to work immediately
413 // when plugging into system, so a HotPlugDeviceGuid is installed onto
414 // the usb keyboard device handle, to distinguish it from other conventional
415 // console devices.
416 //
417 Status = gBS->InstallMultipleProtocolInterfaces (
418 &Controller,
419 &gEfiSimpleTextInProtocolGuid,
420 &UsbKeyboardDevice->SimpleInput,
421 &gEfiSimpleTextInputExProtocolGuid,
422 &UsbKeyboardDevice->SimpleInputEx,
423 &gEfiHotPlugDeviceGuid,
424 NULL,
425 NULL
426 );
427 if (EFI_ERROR (Status)) {
428 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
429 gBS->FreePool (UsbKeyboardDevice);
430 gBS->CloseProtocol (
431 Controller,
432 &gEfiUsbIoProtocolGuid,
433 This->DriverBindingHandle,
434 Controller
435 );
436 return Status;
437 }
438
439 //
440 // Reset USB Keyboard Device
441 //
442 Status = UsbKeyboardDevice->SimpleInput.Reset (
443 &UsbKeyboardDevice->SimpleInput,
444 TRUE
445 );
446 if (EFI_ERROR (Status)) {
447 gBS->UninstallMultipleProtocolInterfaces (
448 Controller,
449 &gEfiSimpleTextInProtocolGuid,
450 &UsbKeyboardDevice->SimpleInput,
451 &gEfiSimpleTextInputExProtocolGuid,
452 &UsbKeyboardDevice->SimpleInputEx,
453 &gEfiHotPlugDeviceGuid,
454 NULL,
455 NULL
456 );
457 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
458 gBS->FreePool (UsbKeyboardDevice);
459 gBS->CloseProtocol (
460 Controller,
461 &gEfiUsbIoProtocolGuid,
462 This->DriverBindingHandle,
463 Controller
464 );
465 return Status;
466 }
467 //
468 // submit async interrupt transfer
469 //
470 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
471 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
472 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
473
474 Status = UsbIo->UsbAsyncInterruptTransfer (
475 UsbIo,
476 EndpointAddr,
477 TRUE,
478 PollingInterval,
479 PacketSize,
480 KeyboardHandler,
481 UsbKeyboardDevice
482 );
483
484 if (EFI_ERROR (Status)) {
485
486 gBS->UninstallMultipleProtocolInterfaces (
487 Controller,
488 &gEfiSimpleTextInProtocolGuid,
489 &UsbKeyboardDevice->SimpleInput,
490 &gEfiSimpleTextInputExProtocolGuid,
491 &UsbKeyboardDevice->SimpleInputEx,
492 &gEfiHotPlugDeviceGuid,
493 NULL,
494 NULL
495 );
496 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
497 gBS->FreePool (UsbKeyboardDevice);
498 gBS->CloseProtocol (
499 Controller,
500 &gEfiUsbIoProtocolGuid,
501 This->DriverBindingHandle,
502 Controller
503 );
504 return Status;
505 }
506
507 UsbKeyboardDevice->ControllerNameTable = NULL;
508 AddUnicodeString2 (
509 "eng",
510 gUsbKeyboardComponentName.SupportedLanguages,
511 &UsbKeyboardDevice->ControllerNameTable,
512 L"Generic Usb Keyboard",
513 TRUE
514 );
515 AddUnicodeString2 (
516 "en",
517 gUsbKeyboardComponentName2.SupportedLanguages,
518 &UsbKeyboardDevice->ControllerNameTable,
519 L"Generic Usb Keyboard",
520 FALSE
521 );
522
523
524 return EFI_SUCCESS;
525
526 ErrorExit:
527 if (UsbKeyboardDevice != NULL) {
528 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
529 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
530 }
531 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
532 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
533 }
534 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
535 gBS->FreePool (UsbKeyboardDevice);
536 UsbKeyboardDevice = NULL;
537 }
538 gBS->CloseProtocol (
539 Controller,
540 &gEfiUsbIoProtocolGuid,
541 This->DriverBindingHandle,
542 Controller
543 );
544 return Status;
545
546 }
547
548
549
550 /**
551 Stop.
552
553 @param This EFI_DRIVER_BINDING_PROTOCOL
554 @param Controller Controller handle
555 @param NumberOfChildren Child handle number
556 @param ChildHandleBuffer Child handle buffer
557
558 @retval EFI_SUCCESS Success
559 @retval EFI_UNSUPPORTED Can't support
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 USBKeyboardDriverBindingStop (
565 IN EFI_DRIVER_BINDING_PROTOCOL *This,
566 IN EFI_HANDLE Controller,
567 IN UINTN NumberOfChildren,
568 IN EFI_HANDLE *ChildHandleBuffer
569 )
570 {
571 EFI_STATUS Status;
572 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
573 USB_KB_DEV *UsbKeyboardDevice;
574
575 Status = gBS->OpenProtocol (
576 Controller,
577 &gEfiSimpleTextInProtocolGuid,
578 (VOID **) &SimpleInput,
579 This->DriverBindingHandle,
580 Controller,
581 EFI_OPEN_PROTOCOL_GET_PROTOCOL
582 );
583 if (EFI_ERROR (Status)) {
584 return EFI_UNSUPPORTED;
585 }
586 Status = gBS->OpenProtocol (
587 Controller,
588 &gEfiSimpleTextInputExProtocolGuid,
589 NULL,
590 This->DriverBindingHandle,
591 Controller,
592 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
593 );
594 if (EFI_ERROR (Status)) {
595 return EFI_UNSUPPORTED;
596 }
597 //
598 // Get USB_KB_DEV instance.
599 //
600 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
601
602 gBS->CloseProtocol (
603 Controller,
604 &gEfiSimpleTextInProtocolGuid,
605 This->DriverBindingHandle,
606 Controller
607 );
608
609 //
610 // Uninstall the Asyn Interrupt Transfer from this device
611 // will disable the key data input from this device
612 //
613 KbdReportStatusCode (
614 UsbKeyboardDevice->DevicePath,
615 EFI_PROGRESS_CODE,
616 PcdGet32 (PcdStatusCodeValueKeyboardDisable)
617 );
618
619 //
620 // Destroy asynchronous interrupt transfer
621 //
622 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
623 UsbKeyboardDevice->UsbIo,
624 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
625 FALSE,
626 UsbKeyboardDevice->IntEndpointDescriptor.Interval,
627 0,
628 NULL,
629 NULL
630 );
631
632 gBS->CloseProtocol (
633 Controller,
634 &gEfiUsbIoProtocolGuid,
635 This->DriverBindingHandle,
636 Controller
637 );
638
639 Status = gBS->UninstallMultipleProtocolInterfaces (
640 Controller,
641 &gEfiSimpleTextInProtocolGuid,
642 &UsbKeyboardDevice->SimpleInput,
643 &gEfiSimpleTextInputExProtocolGuid,
644 &UsbKeyboardDevice->SimpleInputEx,
645 &gEfiHotPlugDeviceGuid,
646 NULL,
647 NULL
648 );
649 //
650 // free all the resources.
651 //
652 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
653 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
654 gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey);
655 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
656 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
657
658 ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
659 gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
660
661 if (UsbKeyboardDevice->ControllerNameTable != NULL) {
662 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
663 }
664
665 gBS->FreePool (UsbKeyboardDevice);
666
667 return Status;
668
669 }
670
671 STATIC
672 EFI_STATUS
673 USBKeyboardReadKeyStrokeWorker (
674 IN USB_KB_DEV *UsbKeyboardDevice,
675 OUT EFI_KEY_DATA *KeyData
676 )
677 /*++
678
679 Routine Description:
680 Reads the next keystroke from the input device. The WaitForKey Event can
681 be used to test for existance of a keystroke via WaitForEvent () call.
682
683 Arguments:
684 UsbKeyboardDevice - Usb keyboard private structure.
685 KeyData - A pointer to a buffer that is filled in with the keystroke
686 state data for the key that was pressed.
687
688 Returns:
689 EFI_SUCCESS - The keystroke information was returned.
690 EFI_NOT_READY - There was no keystroke data availiable.
691 EFI_DEVICE_ERROR - The keystroke information was not returned due to
692 hardware errors.
693 EFI_INVALID_PARAMETER - KeyData is NULL.
694
695 --*/
696 {
697
698 EFI_STATUS Status;
699 UINT8 KeyChar;
700 LIST_ENTRY *Link;
701 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
702 EFI_KEY_DATA OriginalKeyData;
703
704 if (KeyData == NULL) {
705 return EFI_INVALID_PARAMETER;
706 }
707
708 //
709 // if there is no saved ASCII byte, fetch it
710 // by calling USBKeyboardCheckForKey().
711 //
712 if (UsbKeyboardDevice->CurKeyChar == 0) {
713 Status = USBKeyboardCheckForKey (UsbKeyboardDevice);
714 if (EFI_ERROR (Status)) {
715 return Status;
716 }
717 }
718
719 KeyData->Key.UnicodeChar = 0;
720 KeyData->Key.ScanCode = SCAN_NULL;
721
722 KeyChar = UsbKeyboardDevice->CurKeyChar;
723
724 UsbKeyboardDevice->CurKeyChar = 0;
725
726 //
727 // Translate saved ASCII byte into EFI_INPUT_KEY
728 //
729 Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, &KeyData->Key);
730 if (EFI_ERROR (Status)) {
731 return Status;
732 }
733
734 CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState));
735
736 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
737 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
738
739 //
740 //Switch the control value to their original characters. In USBKeyCodeToEFIScanCode() the CTRL-Alpha characters have been switched to
741 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.
742 //
743 CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA));
744 if (UsbKeyboardDevice->CtrlOn) {
745 if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {
746 if (UsbKeyboardDevice->CapsOn) {
747 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1);
748 } else {
749 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1);
750 }
751 }
752 }
753
754 //
755 // Invoke notification functions if exist
756 //
757 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
758 CurrentNotify = CR (
759 Link,
760 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
761 NotifyEntry,
762 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
763 );
764 if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) {
765 CurrentNotify->KeyNotificationFn (&OriginalKeyData);
766 }
767 }
768
769 return EFI_SUCCESS;
770
771 }
772 EFI_STATUS
773 EFIAPI
774 USBKeyboardReset (
775 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
776 IN BOOLEAN ExtendedVerification
777 )
778 {
779 EFI_STATUS Status;
780 USB_KB_DEV *UsbKeyboardDevice;
781
782 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
783
784 KbdReportStatusCode (
785 UsbKeyboardDevice->DevicePath,
786 EFI_PROGRESS_CODE,
787 PcdGet32 (PcdStatusCodeValueKeyboardReset)
788 );
789
790 //
791 // Non Exhaustive reset:
792 // only reset private data structures.
793 //
794 if (!ExtendedVerification) {
795 //
796 // Clear the key buffer of this Usb keyboard
797 //
798 KbdReportStatusCode (
799 UsbKeyboardDevice->DevicePath,
800 EFI_PROGRESS_CODE,
801 PcdGet32 (PcdStatusCodeValueKeyboardClearBuffer)
802 );
803
804 InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));
805 UsbKeyboardDevice->CurKeyChar = 0;
806 return EFI_SUCCESS;
807 }
808
809 //
810 // Exhaustive reset
811 //
812 Status = InitUSBKeyboard (UsbKeyboardDevice);
813 UsbKeyboardDevice->CurKeyChar = 0;
814 if (EFI_ERROR (Status)) {
815 return EFI_DEVICE_ERROR;
816 }
817
818 return EFI_SUCCESS;
819 }
820
821
822 /**
823 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function.
824
825 This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
826 Key A pointer to a buffer that is filled in with the keystroke
827 information for the key that was pressed.
828
829 @retval EFI_SUCCESS Success
830
831 **/
832 STATIC
833 EFI_STATUS
834 EFIAPI
835 USBKeyboardReadKeyStroke (
836 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
837 OUT EFI_INPUT_KEY *Key
838 )
839 {
840 USB_KB_DEV *UsbKeyboardDevice;
841 EFI_STATUS Status;
842 EFI_KEY_DATA KeyData;
843
844 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
845
846 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
847 if (EFI_ERROR (Status)) {
848 return Status;
849 }
850
851 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
852
853 return EFI_SUCCESS;
854
855 }
856
857
858 /**
859 Handler function for WaitForKey event.
860
861 Event Event to be signaled when a key is pressed.
862 Context Points to USB_KB_DEV instance.
863
864 @return VOID
865
866 **/
867 STATIC
868 VOID
869 EFIAPI
870 USBKeyboardWaitForKey (
871 IN EFI_EVENT Event,
872 IN VOID *Context
873 )
874 {
875 USB_KB_DEV *UsbKeyboardDevice;
876
877 UsbKeyboardDevice = (USB_KB_DEV *) Context;
878
879 if (UsbKeyboardDevice->CurKeyChar == 0) {
880
881 if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {
882 return ;
883 }
884 }
885 //
886 // If has key pending, signal the event.
887 //
888 gBS->SignalEvent (Event);
889 }
890
891
892
893 /**
894 Check whether there is key pending.
895
896 UsbKeyboardDevice The USB_KB_DEV instance.
897
898 @retval EFI_SUCCESS Success
899
900 **/
901 STATIC
902 EFI_STATUS
903 USBKeyboardCheckForKey (
904 IN USB_KB_DEV *UsbKeyboardDevice
905 )
906 {
907 EFI_STATUS Status;
908 UINT8 KeyChar;
909
910 //
911 // Fetch raw data from the USB keyboard input,
912 // and translate it into ASCII data.
913 //
914 Status = USBParseKey (UsbKeyboardDevice, &KeyChar);
915 if (EFI_ERROR (Status)) {
916 return Status;
917 }
918
919 UsbKeyboardDevice->CurKeyChar = KeyChar;
920 return EFI_SUCCESS;
921 }
922
923
924 /**
925 Report Status Code in Usb Bot Driver
926
927 @param DevicePath Use this to get Device Path
928 @param CodeType Status Code Type
929 @param CodeValue Status Code Value
930
931 @return None
932
933 **/
934 VOID
935 KbdReportStatusCode (
936 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
937 IN EFI_STATUS_CODE_TYPE CodeType,
938 IN EFI_STATUS_CODE_VALUE Value
939 )
940 {
941
942 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
943 CodeType,
944 Value,
945 DevicePath
946 );
947 }
948 STATIC
949 EFI_STATUS
950 KbdFreeNotifyList (
951 IN OUT LIST_ENTRY *ListHead
952 )
953 /*++
954
955 Routine Description:
956
957 Arguments:
958
959 ListHead - The list head
960
961 Returns:
962
963 EFI_SUCCESS - Free the notify list successfully
964 EFI_INVALID_PARAMETER - ListHead is invalid.
965
966 --*/
967 {
968 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
969
970 if (ListHead == NULL) {
971 return EFI_INVALID_PARAMETER;
972 }
973 while (!IsListEmpty (ListHead)) {
974 NotifyNode = CR (
975 ListHead->ForwardLink,
976 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
977 NotifyEntry,
978 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
979 );
980 RemoveEntryList (ListHead->ForwardLink);
981 gBS->FreePool (NotifyNode);
982 }
983
984 return EFI_SUCCESS;
985 }
986
987 STATIC
988 BOOLEAN
989 IsKeyRegistered (
990 IN EFI_KEY_DATA *RegsiteredData,
991 IN EFI_KEY_DATA *InputData
992 )
993 /*++
994
995 Routine Description:
996
997 Arguments:
998
999 RegsiteredData - A pointer to a buffer that is filled in with the keystroke
1000 state data for the key that was registered.
1001 InputData - A pointer to a buffer that is filled in with the keystroke
1002 state data for the key that was pressed.
1003
1004 Returns:
1005 TRUE - Key be pressed matches a registered key.
1006 FLASE - Match failed.
1007
1008 --*/
1009 {
1010 ASSERT (RegsiteredData != NULL && InputData != NULL);
1011
1012 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
1013 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
1014 return FALSE;
1015 }
1016
1017 //
1018 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
1019 //
1020 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
1021 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
1022 return FALSE;
1023 }
1024 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
1025 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
1026 return FALSE;
1027 }
1028
1029 return TRUE;
1030
1031 }
1032
1033 //
1034 // Simple Text Input Ex protocol functions
1035 //
1036 EFI_STATUS
1037 EFIAPI
1038 USBKeyboardResetEx (
1039 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1040 IN BOOLEAN ExtendedVerification
1041 )
1042 /*++
1043
1044 Routine Description:
1045 Reset the input device and optionaly run diagnostics
1046
1047 Arguments:
1048 This - Protocol instance pointer.
1049 ExtendedVerification - Driver may perform diagnostics on reset.
1050
1051 Returns:
1052 EFI_SUCCESS - The device was reset.
1053 EFI_DEVICE_ERROR - The device is not functioning properly and could
1054 not be reset.
1055
1056 --*/
1057 {
1058 EFI_STATUS Status;
1059 USB_KB_DEV *UsbKeyboardDevice;
1060 EFI_TPL OldTpl;
1061
1062
1063 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1064
1065 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
1066 if (EFI_ERROR (Status)) {
1067 return EFI_DEVICE_ERROR;
1068 }
1069
1070 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1071 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
1072 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
1073 gBS->RestoreTPL (OldTpl);
1074
1075 return EFI_SUCCESS;
1076
1077 }
1078
1079 EFI_STATUS
1080 EFIAPI
1081 USBKeyboardReadKeyStrokeEx (
1082 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1083 OUT EFI_KEY_DATA *KeyData
1084 )
1085 /*++
1086
1087 Routine Description:
1088 Reads the next keystroke from the input device. The WaitForKey Event can
1089 be used to test for existance of a keystroke via WaitForEvent () call.
1090
1091 Arguments:
1092 This - Protocol instance pointer.
1093 KeyData - A pointer to a buffer that is filled in with the keystroke
1094 state data for the key that was pressed.
1095
1096 Returns:
1097 EFI_SUCCESS - The keystroke information was returned.
1098 EFI_NOT_READY - There was no keystroke data availiable.
1099 EFI_DEVICE_ERROR - The keystroke information was not returned due to
1100 hardware errors.
1101 EFI_INVALID_PARAMETER - KeyData is NULL.
1102
1103 --*/
1104 {
1105 USB_KB_DEV *UsbKeyboardDevice;
1106
1107 if (KeyData == NULL) {
1108 return EFI_INVALID_PARAMETER;
1109 }
1110
1111 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1112
1113 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
1114
1115 }
1116
1117 EFI_STATUS
1118 EFIAPI
1119 USBKeyboardSetState (
1120 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1121 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
1122 )
1123 /*++
1124
1125 Routine Description:
1126 Set certain state for the input device.
1127
1128 Arguments:
1129 This - Protocol instance pointer.
1130 KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
1131 state for the input device.
1132
1133 Returns:
1134 EFI_SUCCESS - The device state was set successfully.
1135 EFI_DEVICE_ERROR - The device is not functioning correctly and could
1136 not have the setting adjusted.
1137 EFI_UNSUPPORTED - The device does not have the ability to set its state.
1138 EFI_INVALID_PARAMETER - KeyToggleState is NULL.
1139
1140 --*/
1141 {
1142 USB_KB_DEV *UsbKeyboardDevice;
1143
1144 if (KeyToggleState == NULL) {
1145 return EFI_INVALID_PARAMETER;
1146 }
1147
1148 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1149
1150 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
1151 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
1152 return EFI_UNSUPPORTED;
1153 }
1154
1155 //
1156 // Update the status light
1157 //
1158
1159 UsbKeyboardDevice->ScrollOn = 0;
1160 UsbKeyboardDevice->NumLockOn = 0;
1161 UsbKeyboardDevice->CapsOn = 0;
1162
1163 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
1164 UsbKeyboardDevice->ScrollOn = 1;
1165 }
1166 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
1167 UsbKeyboardDevice->NumLockOn = 1;
1168 }
1169 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
1170 UsbKeyboardDevice->CapsOn = 1;
1171 }
1172
1173 SetKeyLED (UsbKeyboardDevice);
1174
1175 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
1176
1177 return EFI_SUCCESS;
1178
1179 }
1180
1181 EFI_STATUS
1182 EFIAPI
1183 USBKeyboardRegisterKeyNotify (
1184 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1185 IN EFI_KEY_DATA *KeyData,
1186 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
1187 OUT EFI_HANDLE *NotifyHandle
1188 )
1189 /*++
1190
1191 Routine Description:
1192 Register a notification function for a particular keystroke for the input device.
1193
1194 Arguments:
1195 This - Protocol instance pointer.
1196 KeyData - A pointer to a buffer that is filled in with the keystroke
1197 information data for the key that was pressed.
1198 KeyNotificationFunction - Points to the function to be called when the key
1199 sequence is typed specified by KeyData.
1200 NotifyHandle - Points to the unique handle assigned to the registered notification.
1201
1202 Returns:
1203 EFI_SUCCESS - The notification function was registered successfully.
1204 EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
1205 EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
1206
1207 --*/
1208 {
1209 USB_KB_DEV *UsbKeyboardDevice;
1210 EFI_STATUS Status;
1211 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1212 LIST_ENTRY *Link;
1213 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1214
1215 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1216 return EFI_INVALID_PARAMETER;
1217 }
1218
1219 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1220
1221 //
1222 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1223 //
1224 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
1225 CurrentNotify = CR (
1226 Link,
1227 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1228 NotifyEntry,
1229 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1230 );
1231 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1232 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1233 *NotifyHandle = CurrentNotify->NotifyHandle;
1234 return EFI_SUCCESS;
1235 }
1236 }
1237 }
1238
1239 //
1240 // Allocate resource to save the notification function
1241 //
1242 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1243 if (NewNotify == NULL) {
1244 return EFI_OUT_OF_RESOURCES;
1245 }
1246
1247 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1248 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1249 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1250 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1251
1252 //
1253 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
1254 //
1255 Status = gBS->InstallMultipleProtocolInterfaces (
1256 &NewNotify->NotifyHandle,
1257 &gSimpleTextInExNotifyGuid,
1258 NULL,
1259 NULL
1260 );
1261 ASSERT_EFI_ERROR (Status);
1262
1263 *NotifyHandle = NewNotify->NotifyHandle;
1264
1265 return EFI_SUCCESS;
1266
1267 }
1268
1269 EFI_STATUS
1270 EFIAPI
1271 USBKeyboardUnregisterKeyNotify (
1272 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1273 IN EFI_HANDLE NotificationHandle
1274 )
1275 /*++
1276
1277 Routine Description:
1278 Remove a registered notification function from a particular keystroke.
1279
1280 Arguments:
1281 This - Protocol instance pointer.
1282 NotificationHandle - The handle of the notification function being unregistered.
1283
1284 Returns:
1285 EFI_SUCCESS - The notification function was unregistered successfully.
1286 EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
1287 EFI_NOT_FOUND - Can not find the matching entry in database.
1288
1289 --*/
1290 {
1291 USB_KB_DEV *UsbKeyboardDevice;
1292 EFI_STATUS Status;
1293 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1294 LIST_ENTRY *Link;
1295
1296 if (NotificationHandle == NULL) {
1297 return EFI_INVALID_PARAMETER;
1298 }
1299
1300 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1301
1302 Status = gBS->OpenProtocol (
1303 NotificationHandle,
1304 &gSimpleTextInExNotifyGuid,
1305 NULL,
1306 NULL,
1307 NULL,
1308 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1309 );
1310 if (EFI_ERROR (Status)) {
1311 return EFI_INVALID_PARAMETER;
1312 }
1313
1314 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
1315 CurrentNotify = CR (
1316 Link,
1317 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1318 NotifyEntry,
1319 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1320 );
1321 if (CurrentNotify->NotifyHandle == NotificationHandle) {
1322 //
1323 // Remove the notification function from NotifyList and free resources
1324 //
1325 RemoveEntryList (&CurrentNotify->NotifyEntry);
1326 Status = gBS->UninstallMultipleProtocolInterfaces (
1327 CurrentNotify->NotifyHandle,
1328 &gSimpleTextInExNotifyGuid,
1329 NULL,
1330 NULL
1331 );
1332 ASSERT_EFI_ERROR (Status);
1333 gBS->FreePool (CurrentNotify);
1334 return EFI_SUCCESS;
1335 }
1336 }
1337
1338 return EFI_NOT_FOUND;
1339 }
1340