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