3 PS/2 Keyboard driver. Routines that interacts with callers,
4 conforming to EFI driver model
6 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "Ps2Keyboard.h"
14 // Function prototypes
17 Test controller is a keyboard Controller.
19 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
20 @param Controller driver's controller
21 @param RemainingDevicePath children device path
23 @retval EFI_UNSUPPORTED controller is not floppy disk
24 @retval EFI_SUCCESS controller is floppy disk
28 KbdControllerDriverSupported (
29 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
30 IN EFI_HANDLE Controller
,
31 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
35 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
37 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
38 @param Controller driver controller handle
39 @param RemainingDevicePath Children's device path
41 @retval whether success to create floppy control instance.
45 KbdControllerDriverStart (
46 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
47 IN EFI_HANDLE Controller
,
48 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
52 Stop this driver on ControllerHandle. Support stopping any child handles
53 created by this driver.
55 @param This Protocol instance pointer.
56 @param ControllerHandle Handle of device to stop driver on
57 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
58 children is zero stop the entire bus driver.
59 @param ChildHandleBuffer List of Child Handles to Stop.
61 @retval EFI_SUCCESS This driver is removed ControllerHandle
62 @retval other This driver was not removed from this device
67 KbdControllerDriverStop (
68 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
69 IN EFI_HANDLE Controller
,
70 IN UINTN NumberOfChildren
,
71 IN EFI_HANDLE
*ChildHandleBuffer
75 Free the waiting key notify list.
77 @param ListHead Pointer to list head
79 @retval EFI_INVALID_PARAMETER ListHead is NULL
80 @retval EFI_SUCCESS Sucess to free NotifyList
84 IN OUT LIST_ENTRY
*ListHead
88 // DriverBinding Protocol Instance
90 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver
= {
91 KbdControllerDriverSupported
,
92 KbdControllerDriverStart
,
93 KbdControllerDriverStop
,
100 Test controller is a keyboard Controller.
102 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
103 @param Controller driver's controller
104 @param RemainingDevicePath children device path
106 @retval EFI_UNSUPPORTED controller is not floppy disk
107 @retval EFI_SUCCESS controller is floppy disk
111 KbdControllerDriverSupported (
112 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
113 IN EFI_HANDLE Controller
,
114 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
118 EFI_SIO_PROTOCOL
*Sio
;
119 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
120 ACPI_HID_DEVICE_PATH
*Acpi
;
123 // Check whether the controller is keyboard.
125 Status
= gBS
->OpenProtocol (
127 &gEfiDevicePathProtocolGuid
,
128 (VOID
**) &DevicePath
,
129 This
->DriverBindingHandle
,
131 EFI_OPEN_PROTOCOL_GET_PROTOCOL
133 if (EFI_ERROR (Status
)) {
138 Acpi
= (ACPI_HID_DEVICE_PATH
*) DevicePath
;
139 DevicePath
= NextDevicePathNode (DevicePath
);
140 } while (!IsDevicePathEnd (DevicePath
));
142 if (DevicePathType (Acpi
) != ACPI_DEVICE_PATH
||
143 (DevicePathSubType (Acpi
) != ACPI_DP
&& DevicePathSubType (Acpi
) != ACPI_EXTENDED_DP
)) {
144 return EFI_UNSUPPORTED
;
147 if (Acpi
->HID
!= EISA_PNP_ID (0x303) || Acpi
->UID
!= 0) {
148 return EFI_UNSUPPORTED
;
152 // Open the IO Abstraction(s) needed to perform the supported test
154 Status
= gBS
->OpenProtocol (
156 &gEfiSioProtocolGuid
,
158 This
->DriverBindingHandle
,
160 EFI_OPEN_PROTOCOL_BY_DRIVER
162 if (EFI_ERROR (Status
)) {
167 // Close the I/O Abstraction(s) used to perform the supported test
171 &gEfiSioProtocolGuid
,
172 This
->DriverBindingHandle
,
180 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
182 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
183 @param Controller driver controller handle
184 @param RemainingDevicePath Children's device path
186 @retval whether success to create floppy control instance.
190 KbdControllerDriverStart (
191 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
192 IN EFI_HANDLE Controller
,
193 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
198 EFI_SIO_PROTOCOL
*Sio
;
199 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
201 EFI_STATUS_CODE_VALUE StatusCode
;
202 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
206 Status
= gBS
->OpenProtocol (
208 &gEfiDevicePathProtocolGuid
,
209 (VOID
**) &DevicePath
,
210 This
->DriverBindingHandle
,
212 EFI_OPEN_PROTOCOL_GET_PROTOCOL
214 if (EFI_ERROR (Status
)) {
218 // Report that the keyboard is being enabled
220 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
222 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
227 // Get the ISA I/O Protocol on Controller's handle
229 Status
= gBS
->OpenProtocol (
231 &gEfiSioProtocolGuid
,
233 This
->DriverBindingHandle
,
235 EFI_OPEN_PROTOCOL_BY_DRIVER
237 if (EFI_ERROR (Status
)) {
241 // Allocate private data
243 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
244 if (ConsoleIn
== NULL
) {
245 Status
= EFI_OUT_OF_RESOURCES
;
246 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
250 // Setup the device instance
252 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
253 ConsoleIn
->Handle
= Controller
;
254 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
255 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
256 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
257 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
258 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
259 ConsoleIn
->DevicePath
= DevicePath
;
261 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
262 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
263 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
264 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
265 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
267 InitializeListHead (&ConsoleIn
->NotifyList
);
270 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
271 // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
272 // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
273 // So instead we read status register to detect after read if KBC decode is enabled.
277 // Return code is ignored on purpose.
279 if (!PcdGetBool (PcdFastPS2Detection
)) {
280 KeyboardRead (ConsoleIn
, &Data
);
281 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
283 // If nobody decodes KBC I/O port, it will read back as 0xFF.
284 // Check the Time-Out and Parity bit to see if it has an active KBC in system
286 Status
= EFI_DEVICE_ERROR
;
287 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
293 // Setup the WaitForKey event
295 Status
= gBS
->CreateEvent (
300 &((ConsoleIn
->ConIn
).WaitForKey
)
302 if (EFI_ERROR (Status
)) {
303 Status
= EFI_OUT_OF_RESOURCES
;
304 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
308 // Setup the WaitForKeyEx event
310 Status
= gBS
->CreateEvent (
313 KeyboardWaitForKeyEx
,
315 &(ConsoleIn
->ConInEx
.WaitForKeyEx
)
317 if (EFI_ERROR (Status
)) {
318 Status
= EFI_OUT_OF_RESOURCES
;
319 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
322 // Setup a periodic timer, used for reading keystrokes at a fixed interval
324 Status
= gBS
->CreateEvent (
325 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
327 KeyboardTimerHandler
,
329 &ConsoleIn
->TimerEvent
331 if (EFI_ERROR (Status
)) {
332 Status
= EFI_OUT_OF_RESOURCES
;
333 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
337 Status
= gBS
->SetTimer (
338 ConsoleIn
->TimerEvent
,
340 KEYBOARD_TIMER_INTERVAL
342 if (EFI_ERROR (Status
)) {
343 Status
= EFI_OUT_OF_RESOURCES
;
344 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
348 Status
= gBS
->CreateEvent (
351 KeyNotifyProcessHandler
,
353 &ConsoleIn
->KeyNotifyProcessEvent
355 if (EFI_ERROR (Status
)) {
356 Status
= EFI_OUT_OF_RESOURCES
;
357 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
361 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
363 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
368 // Reset the keyboard device
370 Status
= ConsoleIn
->ConInEx
.Reset (&ConsoleIn
->ConInEx
, FeaturePcdGet (PcdPs2KbdExtendedVerification
));
371 if (EFI_ERROR (Status
)) {
372 Status
= EFI_DEVICE_ERROR
;
373 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
377 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
379 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DETECTED
,
383 ConsoleIn
->ControllerNameTable
= NULL
;
386 gPs2KeyboardComponentName
.SupportedLanguages
,
387 &ConsoleIn
->ControllerNameTable
,
388 L
"PS/2 Keyboard Device",
393 gPs2KeyboardComponentName2
.SupportedLanguages
,
394 &ConsoleIn
->ControllerNameTable
,
395 L
"PS/2 Keyboard Device",
401 // Install protocol interfaces for the keyboard device.
403 Status
= gBS
->InstallMultipleProtocolInterfaces (
405 &gEfiSimpleTextInProtocolGuid
,
407 &gEfiSimpleTextInputExProtocolGuid
,
411 if (EFI_ERROR (Status
)) {
412 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
422 if (StatusCode
!= 0) {
423 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
424 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
430 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConIn
.WaitForKey
!= NULL
)) {
431 gBS
->CloseEvent (ConsoleIn
->ConIn
.WaitForKey
);
434 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->TimerEvent
!= NULL
)) {
435 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
437 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
438 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
440 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
)) {
441 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
443 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
444 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
445 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
448 // Since there will be no timer handler for keyboard input any more,
449 // exhaust input data just in case there is still keyboard data left
451 if (ConsoleIn
!= NULL
) {
452 Status1
= EFI_SUCCESS
;
453 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
454 Status1
= KeyboardRead (ConsoleIn
, &Data
);;
458 if (ConsoleIn
!= NULL
) {
459 gBS
->FreePool (ConsoleIn
);
464 &gEfiSioProtocolGuid
,
465 This
->DriverBindingHandle
,
473 Stop this driver on ControllerHandle. Support stopping any child handles
474 created by this driver.
476 @param This Protocol instance pointer.
477 @param ControllerHandle Handle of device to stop driver on
478 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
479 children is zero stop the entire bus driver.
480 @param ChildHandleBuffer List of Child Handles to Stop.
482 @retval EFI_SUCCESS This driver is removed ControllerHandle
483 @retval other This driver was not removed from this device
488 KbdControllerDriverStop (
489 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
490 IN EFI_HANDLE Controller
,
491 IN UINTN NumberOfChildren
,
492 IN EFI_HANDLE
*ChildHandleBuffer
496 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
497 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
503 Status
= gBS
->OpenProtocol (
505 &gEfiSimpleTextInProtocolGuid
,
507 This
->DriverBindingHandle
,
509 EFI_OPEN_PROTOCOL_GET_PROTOCOL
511 if (EFI_ERROR (Status
)) {
514 Status
= gBS
->OpenProtocol (
516 &gEfiSimpleTextInputExProtocolGuid
,
518 This
->DriverBindingHandle
,
520 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
522 if (EFI_ERROR (Status
)) {
526 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
529 // Report that the keyboard is being disabled
531 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
533 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
534 ConsoleIn
->DevicePath
537 if (ConsoleIn
->TimerEvent
!= NULL
) {
538 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
539 ConsoleIn
->TimerEvent
= NULL
;
543 // Since there will be no timer handler for keyboard input any more,
544 // exhaust input data just in case there is still keyboard data left
546 Status
= EFI_SUCCESS
;
547 while (!EFI_ERROR (Status
)) {
548 Status
= KeyboardRead (ConsoleIn
, &Data
);;
551 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
553 Status
= gBS
->UninstallMultipleProtocolInterfaces (
555 &gEfiSimpleTextInProtocolGuid
,
557 &gEfiSimpleTextInputExProtocolGuid
,
561 if (EFI_ERROR (Status
)) {
567 &gEfiSioProtocolGuid
,
568 This
->DriverBindingHandle
,
573 // Free other resources
575 if ((ConsoleIn
->ConIn
).WaitForKey
!= NULL
) {
576 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
577 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
579 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
580 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
581 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
583 if (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
) {
584 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
585 ConsoleIn
->KeyNotifyProcessEvent
= NULL
;
587 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
588 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
589 gBS
->FreePool (ConsoleIn
);
595 Free the waiting key notify list.
597 @param ListHead Pointer to list head
599 @retval EFI_INVALID_PARAMETER ListHead is NULL
600 @retval EFI_SUCCESS Sucess to free NotifyList
604 IN OUT LIST_ENTRY
*ListHead
607 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
609 if (ListHead
== NULL
) {
610 return EFI_INVALID_PARAMETER
;
612 while (!IsListEmpty (ListHead
)) {
614 ListHead
->ForwardLink
,
615 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
617 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
619 RemoveEntryList (ListHead
->ForwardLink
);
620 gBS
->FreePool (NotifyNode
);
627 The module Entry Point for module Ps2Keyboard.
629 @param[in] ImageHandle The firmware allocated handle for the EFI image.
630 @param[in] SystemTable A pointer to the EFI System Table.
632 @retval EFI_SUCCESS The entry point is executed successfully.
633 @retval other Some error occurs when executing this entry point.
638 InitializePs2Keyboard(
639 IN EFI_HANDLE ImageHandle
,
640 IN EFI_SYSTEM_TABLE
*SystemTable
646 // Install driver model protocol(s).
648 Status
= EfiLibInstallDriverBindingComponentName2 (
651 &gKeyboardControllerDriver
,
653 &gPs2KeyboardComponentName
,
654 &gPs2KeyboardComponentName2
656 ASSERT_EFI_ERROR (Status
);