]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c
Update to support EFI_SIMPLE_INPUT_EX protocol
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / efikey.c
1 /** @file
2
3 Copyright (c) 2004 - 2007, 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 = gBS->CreateEvent (
386 EVT_NOTIFY_WAIT,
387 TPL_NOTIFY,
388 USBKeyboardWaitForKey,
389 UsbKeyboardDevice,
390 &(UsbKeyboardDevice->SimpleInput.WaitForKey)
391 );
392
393 if (EFI_ERROR (Status)) {
394 gBS->FreePool (UsbKeyboardDevice);
395 gBS->CloseProtocol (
396 Controller,
397 &gEfiUsbIoProtocolGuid,
398 This->DriverBindingHandle,
399 Controller
400 );
401 return Status;
402 }
403
404 //
405 // Install simple txt in protocol interface
406 // for the usb keyboard device.
407 // Usb keyboard is a hot plug device, and expected to work immediately
408 // when plugging into system, so a HotPlugDeviceGuid is installed onto
409 // the usb keyboard device handle, to distinguish it from other conventional
410 // console devices.
411 //
412 Status = gBS->InstallMultipleProtocolInterfaces (
413 &Controller,
414 &gEfiSimpleTextInProtocolGuid,
415 &UsbKeyboardDevice->SimpleInput,
416 &gEfiSimpleTextInputExProtocolGuid,
417 &UsbKeyboardDevice->SimpleInputEx,
418 &gEfiHotPlugDeviceGuid,
419 NULL,
420 NULL
421 );
422 if (EFI_ERROR (Status)) {
423 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
424 gBS->FreePool (UsbKeyboardDevice);
425 gBS->CloseProtocol (
426 Controller,
427 &gEfiUsbIoProtocolGuid,
428 This->DriverBindingHandle,
429 Controller
430 );
431 return Status;
432 }
433
434 //
435 // Reset USB Keyboard Device
436 //
437 Status = UsbKeyboardDevice->SimpleInput.Reset (
438 &UsbKeyboardDevice->SimpleInput,
439 TRUE
440 );
441 if (EFI_ERROR (Status)) {
442 gBS->UninstallMultipleProtocolInterfaces (
443 Controller,
444 &gEfiSimpleTextInProtocolGuid,
445 &UsbKeyboardDevice->SimpleInput,
446 &gEfiSimpleTextInputExProtocolGuid,
447 &UsbKeyboardDevice->SimpleInputEx,
448 &gEfiHotPlugDeviceGuid,
449 NULL,
450 NULL
451 );
452 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
453 gBS->FreePool (UsbKeyboardDevice);
454 gBS->CloseProtocol (
455 Controller,
456 &gEfiUsbIoProtocolGuid,
457 This->DriverBindingHandle,
458 Controller
459 );
460 return Status;
461 }
462 //
463 // submit async interrupt transfer
464 //
465 EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
466 PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
467 PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
468
469 Status = UsbIo->UsbAsyncInterruptTransfer (
470 UsbIo,
471 EndpointAddr,
472 TRUE,
473 PollingInterval,
474 PacketSize,
475 KeyboardHandler,
476 UsbKeyboardDevice
477 );
478
479 if (EFI_ERROR (Status)) {
480
481 gBS->UninstallMultipleProtocolInterfaces (
482 Controller,
483 &gEfiSimpleTextInProtocolGuid,
484 &UsbKeyboardDevice->SimpleInput,
485 &gEfiSimpleTextInputExProtocolGuid,
486 &UsbKeyboardDevice->SimpleInputEx,
487 &gEfiHotPlugDeviceGuid,
488 NULL,
489 NULL
490 );
491 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
492 gBS->FreePool (UsbKeyboardDevice);
493 gBS->CloseProtocol (
494 Controller,
495 &gEfiUsbIoProtocolGuid,
496 This->DriverBindingHandle,
497 Controller
498 );
499 return Status;
500 }
501
502 UsbKeyboardDevice->ControllerNameTable = NULL;
503 AddUnicodeString2 (
504 "eng",
505 gUsbKeyboardComponentName.SupportedLanguages,
506 &UsbKeyboardDevice->ControllerNameTable,
507 L"Generic Usb Keyboard",
508 TRUE
509 );
510 AddUnicodeString2 (
511 "en",
512 gUsbKeyboardComponentName2.SupportedLanguages,
513 &UsbKeyboardDevice->ControllerNameTable,
514 L"Generic Usb Keyboard",
515 FALSE
516 );
517
518
519 return EFI_SUCCESS;
520
521 ErrorExit:
522 if (UsbKeyboardDevice != NULL) {
523 if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
524 gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
525 }
526 if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
527 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
528 }
529 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
530 gBS->FreePool (UsbKeyboardDevice);
531 UsbKeyboardDevice = NULL;
532 }
533 gBS->CloseProtocol (
534 Controller,
535 &gEfiUsbIoProtocolGuid,
536 This->DriverBindingHandle,
537 Controller
538 );
539 return Status;
540
541 }
542
543
544
545 /**
546 Stop.
547
548 @param This EFI_DRIVER_BINDING_PROTOCOL
549 @param Controller Controller handle
550 @param NumberOfChildren Child handle number
551 @param ChildHandleBuffer Child handle buffer
552
553 @retval EFI_SUCCESS Success
554 @retval EFI_UNSUPPORTED Can't support
555
556 **/
557 EFI_STATUS
558 EFIAPI
559 USBKeyboardDriverBindingStop (
560 IN EFI_DRIVER_BINDING_PROTOCOL *This,
561 IN EFI_HANDLE Controller,
562 IN UINTN NumberOfChildren,
563 IN EFI_HANDLE *ChildHandleBuffer
564 )
565 {
566 EFI_STATUS Status;
567 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
568 USB_KB_DEV *UsbKeyboardDevice;
569
570 Status = gBS->OpenProtocol (
571 Controller,
572 &gEfiSimpleTextInProtocolGuid,
573 (VOID **) &SimpleInput,
574 This->DriverBindingHandle,
575 Controller,
576 EFI_OPEN_PROTOCOL_BY_DRIVER
577 );
578 if (EFI_ERROR (Status)) {
579 return EFI_UNSUPPORTED;
580 }
581 Status = gBS->OpenProtocol (
582 Controller,
583 &gEfiSimpleTextInputExProtocolGuid,
584 NULL,
585 This->DriverBindingHandle,
586 Controller,
587 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
588 );
589 if (EFI_ERROR (Status)) {
590 return EFI_UNSUPPORTED;
591 }
592 //
593 // Get USB_KB_DEV instance.
594 //
595 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
596
597 gBS->CloseProtocol (
598 Controller,
599 &gEfiSimpleTextInProtocolGuid,
600 This->DriverBindingHandle,
601 Controller
602 );
603
604 //
605 // Uninstall the Asyn Interrupt Transfer from this device
606 // will disable the key data input from this device
607 //
608 KbdReportStatusCode (
609 UsbKeyboardDevice->DevicePath,
610 EFI_PROGRESS_CODE,
611 PcdGet32 (PcdStatusCodeValueKeyboardDisable)
612 );
613
614 //
615 // Destroy asynchronous interrupt transfer
616 //
617 UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
618 UsbKeyboardDevice->UsbIo,
619 UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
620 FALSE,
621 UsbKeyboardDevice->IntEndpointDescriptor.Interval,
622 0,
623 NULL,
624 NULL
625 );
626
627 gBS->CloseProtocol (
628 Controller,
629 &gEfiUsbIoProtocolGuid,
630 This->DriverBindingHandle,
631 Controller
632 );
633
634 Status = gBS->UninstallMultipleProtocolInterfaces (
635 Controller,
636 &gEfiSimpleTextInProtocolGuid,
637 &UsbKeyboardDevice->SimpleInput,
638 &gEfiSimpleTextInputExProtocolGuid,
639 &UsbKeyboardDevice->SimpleInputEx,
640 &gEfiHotPlugDeviceGuid,
641 NULL,
642 NULL
643 );
644 //
645 // free all the resources.
646 //
647 gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
648 gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
649 gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey);
650 gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
651 KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
652
653 if (UsbKeyboardDevice->ControllerNameTable != NULL) {
654 FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
655 }
656
657 gBS->FreePool (UsbKeyboardDevice);
658
659 return Status;
660
661 }
662
663 STATIC
664 EFI_STATUS
665 USBKeyboardReadKeyStrokeWorker (
666 IN USB_KB_DEV *UsbKeyboardDevice,
667 OUT EFI_KEY_DATA *KeyData
668 )
669 /*++
670
671 Routine Description:
672 Reads the next keystroke from the input device. The WaitForKey Event can
673 be used to test for existance of a keystroke via WaitForEvent () call.
674
675 Arguments:
676 UsbKeyboardDevice - Usb keyboard private structure.
677 KeyData - A pointer to a buffer that is filled in with the keystroke
678 state data for the key that was pressed.
679
680 Returns:
681 EFI_SUCCESS - The keystroke information was returned.
682 EFI_NOT_READY - There was no keystroke data availiable.
683 EFI_DEVICE_ERROR - The keystroke information was not returned due to
684 hardware errors.
685 EFI_INVALID_PARAMETER - KeyData is NULL.
686
687 --*/
688 {
689
690 EFI_STATUS Status;
691 UINT8 KeyChar;
692 LIST_ENTRY *Link;
693 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
694 EFI_KEY_DATA OriginalKeyData;
695
696 if (KeyData == NULL) {
697 return EFI_INVALID_PARAMETER;
698 }
699
700 //
701 // if there is no saved ASCII byte, fetch it
702 // by calling USBKeyboardCheckForKey().
703 //
704 if (UsbKeyboardDevice->CurKeyChar == 0) {
705 Status = USBKeyboardCheckForKey (UsbKeyboardDevice);
706 if (EFI_ERROR (Status)) {
707 return Status;
708 }
709 }
710
711 KeyData->Key.UnicodeChar = 0;
712 KeyData->Key.ScanCode = SCAN_NULL;
713
714 KeyChar = UsbKeyboardDevice->CurKeyChar;
715
716 UsbKeyboardDevice->CurKeyChar = 0;
717
718 //
719 // Translate saved ASCII byte into EFI_INPUT_KEY
720 //
721 Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, &KeyData->Key);
722 if (EFI_ERROR (Status)) {
723 return Status;
724 }
725
726 CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState));
727
728 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
729 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
730
731 //
732 //Switch the control value to their original characters. In USBKeyCodeToEFIScanCode() the CTRL-Alpha characters have been switched to
733 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.
734 //
735 CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA));
736 if (UsbKeyboardDevice->CtrlOn) {
737 if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {
738 if (UsbKeyboardDevice->CapsOn) {
739 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1);
740 } else {
741 OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1);
742 }
743 }
744 }
745
746 //
747 // Invoke notification functions if exist
748 //
749 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
750 CurrentNotify = CR (
751 Link,
752 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
753 NotifyEntry,
754 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
755 );
756 if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) {
757 CurrentNotify->KeyNotificationFn (&OriginalKeyData);
758 }
759 }
760
761 return EFI_SUCCESS;
762
763 }
764 EFI_STATUS
765 EFIAPI
766 USBKeyboardReset (
767 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
768 IN BOOLEAN ExtendedVerification
769 )
770 {
771 EFI_STATUS Status;
772 USB_KB_DEV *UsbKeyboardDevice;
773
774 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
775
776 KbdReportStatusCode (
777 UsbKeyboardDevice->DevicePath,
778 EFI_PROGRESS_CODE,
779 PcdGet32 (PcdStatusCodeValueKeyboardReset)
780 );
781
782 //
783 // Non Exhaustive reset:
784 // only reset private data structures.
785 //
786 if (!ExtendedVerification) {
787 //
788 // Clear the key buffer of this Usb keyboard
789 //
790 KbdReportStatusCode (
791 UsbKeyboardDevice->DevicePath,
792 EFI_PROGRESS_CODE,
793 PcdGet32 (PcdStatusCodeValueKeyboardClearBuffer)
794 );
795
796 InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));
797 UsbKeyboardDevice->CurKeyChar = 0;
798 return EFI_SUCCESS;
799 }
800
801 //
802 // Exhaustive reset
803 //
804 Status = InitUSBKeyboard (UsbKeyboardDevice);
805 UsbKeyboardDevice->CurKeyChar = 0;
806 if (EFI_ERROR (Status)) {
807 return EFI_DEVICE_ERROR;
808 }
809
810 return EFI_SUCCESS;
811 }
812
813
814 /**
815 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function.
816
817 This The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
818 Key A pointer to a buffer that is filled in with the keystroke
819 information for the key that was pressed.
820
821 @retval EFI_SUCCESS Success
822
823 **/
824 STATIC
825 EFI_STATUS
826 EFIAPI
827 USBKeyboardReadKeyStroke (
828 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
829 OUT EFI_INPUT_KEY *Key
830 )
831 {
832 USB_KB_DEV *UsbKeyboardDevice;
833 EFI_STATUS Status;
834 EFI_KEY_DATA KeyData;
835
836 UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
837
838 Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
839 if (EFI_ERROR (Status)) {
840 return Status;
841 }
842
843 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
844
845 return EFI_SUCCESS;
846
847 }
848
849
850 /**
851 Handler function for WaitForKey event.
852
853 Event Event to be signaled when a key is pressed.
854 Context Points to USB_KB_DEV instance.
855
856 @return VOID
857
858 **/
859 STATIC
860 VOID
861 EFIAPI
862 USBKeyboardWaitForKey (
863 IN EFI_EVENT Event,
864 IN VOID *Context
865 )
866 {
867 USB_KB_DEV *UsbKeyboardDevice;
868
869 UsbKeyboardDevice = (USB_KB_DEV *) Context;
870
871 if (UsbKeyboardDevice->CurKeyChar == 0) {
872
873 if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {
874 return ;
875 }
876 }
877 //
878 // If has key pending, signal the event.
879 //
880 gBS->SignalEvent (Event);
881 }
882
883
884
885 /**
886 Check whether there is key pending.
887
888 UsbKeyboardDevice The USB_KB_DEV instance.
889
890 @retval EFI_SUCCESS Success
891
892 **/
893 STATIC
894 EFI_STATUS
895 USBKeyboardCheckForKey (
896 IN USB_KB_DEV *UsbKeyboardDevice
897 )
898 {
899 EFI_STATUS Status;
900 UINT8 KeyChar;
901
902 //
903 // Fetch raw data from the USB keyboard input,
904 // and translate it into ASCII data.
905 //
906 Status = USBParseKey (UsbKeyboardDevice, &KeyChar);
907 if (EFI_ERROR (Status)) {
908 return Status;
909 }
910
911 UsbKeyboardDevice->CurKeyChar = KeyChar;
912 return EFI_SUCCESS;
913 }
914
915
916 /**
917 Report Status Code in Usb Bot Driver
918
919 @param DevicePath Use this to get Device Path
920 @param CodeType Status Code Type
921 @param CodeValue Status Code Value
922
923 @return None
924
925 **/
926 VOID
927 KbdReportStatusCode (
928 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
929 IN EFI_STATUS_CODE_TYPE CodeType,
930 IN EFI_STATUS_CODE_VALUE Value
931 )
932 {
933
934 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
935 CodeType,
936 Value,
937 DevicePath
938 );
939 }
940 STATIC
941 EFI_STATUS
942 KbdFreeNotifyList (
943 IN OUT LIST_ENTRY *ListHead
944 )
945 /*++
946
947 Routine Description:
948
949 Arguments:
950
951 ListHead - The list head
952
953 Returns:
954
955 EFI_SUCCESS - Free the notify list successfully
956 EFI_INVALID_PARAMETER - ListHead is invalid.
957
958 --*/
959 {
960 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
961
962 if (ListHead == NULL) {
963 return EFI_INVALID_PARAMETER;
964 }
965 while (!IsListEmpty (ListHead)) {
966 NotifyNode = CR (
967 ListHead->ForwardLink,
968 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
969 NotifyEntry,
970 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
971 );
972 RemoveEntryList (ListHead->ForwardLink);
973 gBS->FreePool (NotifyNode);
974 }
975
976 return EFI_SUCCESS;
977 }
978
979 STATIC
980 BOOLEAN
981 IsKeyRegistered (
982 IN EFI_KEY_DATA *RegsiteredData,
983 IN EFI_KEY_DATA *InputData
984 )
985 /*++
986
987 Routine Description:
988
989 Arguments:
990
991 RegsiteredData - A pointer to a buffer that is filled in with the keystroke
992 state data for the key that was registered.
993 InputData - A pointer to a buffer that is filled in with the keystroke
994 state data for the key that was pressed.
995
996 Returns:
997 TRUE - Key be pressed matches a registered key.
998 FLASE - Match failed.
999
1000 --*/
1001 {
1002 ASSERT (RegsiteredData != NULL && InputData != NULL);
1003
1004 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
1005 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
1006 return FALSE;
1007 }
1008
1009 //
1010 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
1011 //
1012 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
1013 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
1014 return FALSE;
1015 }
1016 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
1017 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
1018 return FALSE;
1019 }
1020
1021 return TRUE;
1022
1023 }
1024
1025 //
1026 // Simple Text Input Ex protocol functions
1027 //
1028 EFI_STATUS
1029 EFIAPI
1030 USBKeyboardResetEx (
1031 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1032 IN BOOLEAN ExtendedVerification
1033 )
1034 /*++
1035
1036 Routine Description:
1037 Reset the input device and optionaly run diagnostics
1038
1039 Arguments:
1040 This - Protocol instance pointer.
1041 ExtendedVerification - Driver may perform diagnostics on reset.
1042
1043 Returns:
1044 EFI_SUCCESS - The device was reset.
1045 EFI_DEVICE_ERROR - The device is not functioning properly and could
1046 not be reset.
1047
1048 --*/
1049 {
1050 EFI_STATUS Status;
1051 USB_KB_DEV *UsbKeyboardDevice;
1052 EFI_TPL OldTpl;
1053
1054
1055 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1056
1057 Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
1058 if (EFI_ERROR (Status)) {
1059 return EFI_DEVICE_ERROR;
1060 }
1061
1062 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1063 UsbKeyboardDevice->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
1064 UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
1065 gBS->RestoreTPL (OldTpl);
1066
1067 return EFI_SUCCESS;
1068
1069 }
1070
1071 EFI_STATUS
1072 EFIAPI
1073 USBKeyboardReadKeyStrokeEx (
1074 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1075 OUT EFI_KEY_DATA *KeyData
1076 )
1077 /*++
1078
1079 Routine Description:
1080 Reads the next keystroke from the input device. The WaitForKey Event can
1081 be used to test for existance of a keystroke via WaitForEvent () call.
1082
1083 Arguments:
1084 This - Protocol instance pointer.
1085 KeyData - A pointer to a buffer that is filled in with the keystroke
1086 state data for the key that was pressed.
1087
1088 Returns:
1089 EFI_SUCCESS - The keystroke information was returned.
1090 EFI_NOT_READY - There was no keystroke data availiable.
1091 EFI_DEVICE_ERROR - The keystroke information was not returned due to
1092 hardware errors.
1093 EFI_INVALID_PARAMETER - KeyData is NULL.
1094
1095 --*/
1096 {
1097 USB_KB_DEV *UsbKeyboardDevice;
1098
1099 if (KeyData == NULL) {
1100 return EFI_INVALID_PARAMETER;
1101 }
1102
1103 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1104
1105 return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
1106
1107 }
1108
1109 EFI_STATUS
1110 EFIAPI
1111 USBKeyboardSetState (
1112 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1113 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
1114 )
1115 /*++
1116
1117 Routine Description:
1118 Set certain state for the input device.
1119
1120 Arguments:
1121 This - Protocol instance pointer.
1122 KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
1123 state for the input device.
1124
1125 Returns:
1126 EFI_SUCCESS - The device state was set successfully.
1127 EFI_DEVICE_ERROR - The device is not functioning correctly and could
1128 not have the setting adjusted.
1129 EFI_UNSUPPORTED - The device does not have the ability to set its state.
1130 EFI_INVALID_PARAMETER - KeyToggleState is NULL.
1131
1132 --*/
1133 {
1134 USB_KB_DEV *UsbKeyboardDevice;
1135
1136 if (KeyToggleState == NULL) {
1137 return EFI_INVALID_PARAMETER;
1138 }
1139
1140 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1141
1142 if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
1143 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
1144 return EFI_UNSUPPORTED;
1145 }
1146
1147 //
1148 // Update the status light
1149 //
1150
1151 UsbKeyboardDevice->ScrollOn = 0;
1152 UsbKeyboardDevice->NumLockOn = 0;
1153 UsbKeyboardDevice->CapsOn = 0;
1154
1155 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
1156 UsbKeyboardDevice->ScrollOn = 1;
1157 }
1158 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
1159 UsbKeyboardDevice->NumLockOn = 1;
1160 }
1161 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
1162 UsbKeyboardDevice->CapsOn = 1;
1163 }
1164
1165 SetKeyLED (UsbKeyboardDevice);
1166
1167 UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
1168
1169 return EFI_SUCCESS;
1170
1171 }
1172
1173 EFI_STATUS
1174 EFIAPI
1175 USBKeyboardRegisterKeyNotify (
1176 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1177 IN EFI_KEY_DATA *KeyData,
1178 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
1179 OUT EFI_HANDLE *NotifyHandle
1180 )
1181 /*++
1182
1183 Routine Description:
1184 Register a notification function for a particular keystroke for the input device.
1185
1186 Arguments:
1187 This - Protocol instance pointer.
1188 KeyData - A pointer to a buffer that is filled in with the keystroke
1189 information data for the key that was pressed.
1190 KeyNotificationFunction - Points to the function to be called when the key
1191 sequence is typed specified by KeyData.
1192 NotifyHandle - Points to the unique handle assigned to the registered notification.
1193
1194 Returns:
1195 EFI_SUCCESS - The notification function was registered successfully.
1196 EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
1197 EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
1198
1199 --*/
1200 {
1201 USB_KB_DEV *UsbKeyboardDevice;
1202 EFI_STATUS Status;
1203 KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
1204 LIST_ENTRY *Link;
1205 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1206
1207 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
1208 return EFI_INVALID_PARAMETER;
1209 }
1210
1211 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1212
1213 //
1214 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
1215 //
1216 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
1217 CurrentNotify = CR (
1218 Link,
1219 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1220 NotifyEntry,
1221 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1222 );
1223 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
1224 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
1225 *NotifyHandle = CurrentNotify->NotifyHandle;
1226 return EFI_SUCCESS;
1227 }
1228 }
1229 }
1230
1231 //
1232 // Allocate resource to save the notification function
1233 //
1234 NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
1235 if (NewNotify == NULL) {
1236 return EFI_OUT_OF_RESOURCES;
1237 }
1238
1239 NewNotify->Signature = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
1240 NewNotify->KeyNotificationFn = KeyNotificationFunction;
1241 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
1242 InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
1243
1244 //
1245 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
1246 //
1247 Status = gBS->InstallMultipleProtocolInterfaces (
1248 &NewNotify->NotifyHandle,
1249 &gSimpleTextInExNotifyGuid,
1250 NULL,
1251 NULL
1252 );
1253 ASSERT_EFI_ERROR (Status);
1254
1255 *NotifyHandle = NewNotify->NotifyHandle;
1256
1257 return EFI_SUCCESS;
1258
1259 }
1260
1261 EFI_STATUS
1262 EFIAPI
1263 USBKeyboardUnregisterKeyNotify (
1264 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
1265 IN EFI_HANDLE NotificationHandle
1266 )
1267 /*++
1268
1269 Routine Description:
1270 Remove a registered notification function from a particular keystroke.
1271
1272 Arguments:
1273 This - Protocol instance pointer.
1274 NotificationHandle - The handle of the notification function being unregistered.
1275
1276 Returns:
1277 EFI_SUCCESS - The notification function was unregistered successfully.
1278 EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
1279 EFI_NOT_FOUND - Can not find the matching entry in database.
1280
1281 --*/
1282 {
1283 USB_KB_DEV *UsbKeyboardDevice;
1284 EFI_STATUS Status;
1285 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1286 LIST_ENTRY *Link;
1287
1288 if (NotificationHandle == NULL) {
1289 return EFI_INVALID_PARAMETER;
1290 }
1291
1292 UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
1293
1294 Status = gBS->OpenProtocol (
1295 NotificationHandle,
1296 &gSimpleTextInExNotifyGuid,
1297 NULL,
1298 NULL,
1299 NULL,
1300 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1301 );
1302 if (EFI_ERROR (Status)) {
1303 return EFI_INVALID_PARAMETER;
1304 }
1305
1306 for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {
1307 CurrentNotify = CR (
1308 Link,
1309 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1310 NotifyEntry,
1311 USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1312 );
1313 if (CurrentNotify->NotifyHandle == NotificationHandle) {
1314 //
1315 // Remove the notification function from NotifyList and free resources
1316 //
1317 RemoveEntryList (&CurrentNotify->NotifyEntry);
1318 Status = gBS->UninstallMultipleProtocolInterfaces (
1319 CurrentNotify->NotifyHandle,
1320 &gSimpleTextInExNotifyGuid,
1321 NULL,
1322 NULL
1323 );
1324 ASSERT_EFI_ERROR (Status);
1325 gBS->FreePool (CurrentNotify);
1326 return EFI_SUCCESS;
1327 }
1328 }
1329
1330 return EFI_NOT_FOUND;
1331 }
1332