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