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
18 Test controller is a keyboard Controller.
20 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
21 @param Controller driver's controller
22 @param RemainingDevicePath children device path
24 @retval EFI_UNSUPPORTED controller is not floppy disk
25 @retval EFI_SUCCESS controller is floppy disk
29 KbdControllerDriverSupported (
30 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
31 IN EFI_HANDLE Controller
,
32 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
36 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
38 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
39 @param Controller driver controller handle
40 @param RemainingDevicePath Children's device path
42 @retval whether success to create floppy control instance.
46 KbdControllerDriverStart (
47 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
48 IN EFI_HANDLE Controller
,
49 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
53 Stop this driver on ControllerHandle. Support stopping any child handles
54 created by this driver.
56 @param This Protocol instance pointer.
57 @param ControllerHandle Handle of device to stop driver on
58 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
59 children is zero stop the entire bus driver.
60 @param ChildHandleBuffer List of Child Handles to Stop.
62 @retval EFI_SUCCESS This driver is removed ControllerHandle
63 @retval other This driver was not removed from this device
68 KbdControllerDriverStop (
69 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
70 IN EFI_HANDLE Controller
,
71 IN UINTN NumberOfChildren
,
72 IN EFI_HANDLE
*ChildHandleBuffer
76 Free the waiting key notify list.
78 @param ListHead Pointer to list head
80 @retval EFI_INVALID_PARAMETER ListHead is NULL
81 @retval EFI_SUCCESS Success to free NotifyList
85 IN OUT LIST_ENTRY
*ListHead
89 // DriverBinding Protocol Instance
91 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver
= {
92 KbdControllerDriverSupported
,
93 KbdControllerDriverStart
,
94 KbdControllerDriverStop
,
101 Test controller is a keyboard Controller.
103 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
104 @param Controller driver's controller
105 @param RemainingDevicePath children device path
107 @retval EFI_UNSUPPORTED controller is not floppy disk
108 @retval EFI_SUCCESS controller is floppy disk
112 KbdControllerDriverSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
114 IN EFI_HANDLE Controller
,
115 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
119 EFI_SIO_PROTOCOL
*Sio
;
120 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
121 ACPI_HID_DEVICE_PATH
*Acpi
;
124 // Check whether the controller is keyboard.
126 Status
= gBS
->OpenProtocol (
128 &gEfiDevicePathProtocolGuid
,
129 (VOID
**)&DevicePath
,
130 This
->DriverBindingHandle
,
132 EFI_OPEN_PROTOCOL_GET_PROTOCOL
134 if (EFI_ERROR (Status
)) {
139 Acpi
= (ACPI_HID_DEVICE_PATH
*)DevicePath
;
140 DevicePath
= NextDevicePathNode (DevicePath
);
141 } while (!IsDevicePathEnd (DevicePath
));
143 if ((DevicePathType (Acpi
) != ACPI_DEVICE_PATH
) ||
144 ((DevicePathSubType (Acpi
) != ACPI_DP
) && (DevicePathSubType (Acpi
) != ACPI_EXTENDED_DP
)))
146 return EFI_UNSUPPORTED
;
149 if ((Acpi
->HID
!= EISA_PNP_ID (0x303)) || (Acpi
->UID
!= 0)) {
150 return EFI_UNSUPPORTED
;
154 // Open the IO Abstraction(s) needed to perform the supported test
156 Status
= gBS
->OpenProtocol (
158 &gEfiSioProtocolGuid
,
160 This
->DriverBindingHandle
,
162 EFI_OPEN_PROTOCOL_BY_DRIVER
164 if (EFI_ERROR (Status
)) {
169 // Close the I/O Abstraction(s) used to perform the supported test
173 &gEfiSioProtocolGuid
,
174 This
->DriverBindingHandle
,
182 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
184 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
185 @param Controller driver controller handle
186 @param RemainingDevicePath Children's device path
188 @retval whether success to create floppy control instance.
192 KbdControllerDriverStart (
193 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
194 IN EFI_HANDLE Controller
,
195 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
200 EFI_SIO_PROTOCOL
*Sio
;
201 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
203 EFI_STATUS_CODE_VALUE StatusCode
;
204 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
208 Status
= gBS
->OpenProtocol (
210 &gEfiDevicePathProtocolGuid
,
211 (VOID
**)&DevicePath
,
212 This
->DriverBindingHandle
,
214 EFI_OPEN_PROTOCOL_GET_PROTOCOL
216 if (EFI_ERROR (Status
)) {
221 // Report that the keyboard is being enabled
223 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
225 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
230 // Get the ISA I/O Protocol on Controller's handle
232 Status
= gBS
->OpenProtocol (
234 &gEfiSioProtocolGuid
,
236 This
->DriverBindingHandle
,
238 EFI_OPEN_PROTOCOL_BY_DRIVER
240 if (EFI_ERROR (Status
)) {
245 // Allocate private data
247 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
248 if (ConsoleIn
== NULL
) {
249 Status
= EFI_OUT_OF_RESOURCES
;
250 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
255 // Setup the device instance
257 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
258 ConsoleIn
->Handle
= Controller
;
259 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
260 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
261 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
262 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
263 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
264 ConsoleIn
->DevicePath
= DevicePath
;
266 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
267 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
268 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
269 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
270 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
272 InitializeListHead (&ConsoleIn
->NotifyList
);
275 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
276 // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
277 // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
278 // So instead we read status register to detect after read if KBC decode is enabled.
282 // Return code is ignored on purpose.
284 if (!PcdGetBool (PcdFastPS2Detection
)) {
285 KeyboardRead (ConsoleIn
, &Data
);
286 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
288 // If nobody decodes KBC I/O port, it will read back as 0xFF.
289 // Check the Time-Out and Parity bit to see if it has an active KBC in system
291 Status
= EFI_DEVICE_ERROR
;
292 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
298 // Setup the WaitForKey event
300 Status
= gBS
->CreateEvent (
305 &((ConsoleIn
->ConIn
).WaitForKey
)
307 if (EFI_ERROR (Status
)) {
308 Status
= EFI_OUT_OF_RESOURCES
;
309 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
314 // Setup the WaitForKeyEx event
316 Status
= gBS
->CreateEvent (
319 KeyboardWaitForKeyEx
,
321 &(ConsoleIn
->ConInEx
.WaitForKeyEx
)
323 if (EFI_ERROR (Status
)) {
324 Status
= EFI_OUT_OF_RESOURCES
;
325 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
329 // Setup a periodic timer, used for reading keystrokes at a fixed interval
331 Status
= gBS
->CreateEvent (
332 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
334 KeyboardTimerHandler
,
336 &ConsoleIn
->TimerEvent
338 if (EFI_ERROR (Status
)) {
339 Status
= EFI_OUT_OF_RESOURCES
;
340 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
344 Status
= gBS
->SetTimer (
345 ConsoleIn
->TimerEvent
,
347 KEYBOARD_TIMER_INTERVAL
349 if (EFI_ERROR (Status
)) {
350 Status
= EFI_OUT_OF_RESOURCES
;
351 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
355 Status
= gBS
->CreateEvent (
358 KeyNotifyProcessHandler
,
360 &ConsoleIn
->KeyNotifyProcessEvent
362 if (EFI_ERROR (Status
)) {
363 Status
= EFI_OUT_OF_RESOURCES
;
364 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
368 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
370 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
375 // Reset the keyboard device
377 Status
= ConsoleIn
->ConInEx
.Reset (&ConsoleIn
->ConInEx
, FeaturePcdGet (PcdPs2KbdExtendedVerification
));
378 if (EFI_ERROR (Status
)) {
379 Status
= EFI_DEVICE_ERROR
;
380 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
384 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
386 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DETECTED
,
390 ConsoleIn
->ControllerNameTable
= NULL
;
393 gPs2KeyboardComponentName
.SupportedLanguages
,
394 &ConsoleIn
->ControllerNameTable
,
395 L
"PS/2 Keyboard Device",
400 gPs2KeyboardComponentName2
.SupportedLanguages
,
401 &ConsoleIn
->ControllerNameTable
,
402 L
"PS/2 Keyboard Device",
407 // Install protocol interfaces for the keyboard device.
409 Status
= gBS
->InstallMultipleProtocolInterfaces (
411 &gEfiSimpleTextInProtocolGuid
,
413 &gEfiSimpleTextInputExProtocolGuid
,
417 if (EFI_ERROR (Status
)) {
418 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
428 if (StatusCode
!= 0) {
429 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
430 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
436 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConIn
.WaitForKey
!= NULL
)) {
437 gBS
->CloseEvent (ConsoleIn
->ConIn
.WaitForKey
);
440 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->TimerEvent
!= NULL
)) {
441 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
444 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
445 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
448 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
)) {
449 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
452 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
453 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
454 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
458 // Since there will be no timer handler for keyboard input any more,
459 // exhaust input data just in case there is still keyboard data left
461 if (ConsoleIn
!= NULL
) {
462 Status1
= EFI_SUCCESS
;
463 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
464 Status1
= KeyboardRead (ConsoleIn
, &Data
);
468 if (ConsoleIn
!= NULL
) {
469 gBS
->FreePool (ConsoleIn
);
474 &gEfiSioProtocolGuid
,
475 This
->DriverBindingHandle
,
483 Stop this driver on ControllerHandle. Support stopping any child handles
484 created by this driver.
486 @param This Protocol instance pointer.
487 @param ControllerHandle Handle of device to stop driver on
488 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
489 children is zero stop the entire bus driver.
490 @param ChildHandleBuffer List of Child Handles to Stop.
492 @retval EFI_SUCCESS This driver is removed ControllerHandle
493 @retval other This driver was not removed from this device
498 KbdControllerDriverStop (
499 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
500 IN EFI_HANDLE Controller
,
501 IN UINTN NumberOfChildren
,
502 IN EFI_HANDLE
*ChildHandleBuffer
506 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
507 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
513 Status
= gBS
->OpenProtocol (
515 &gEfiSimpleTextInProtocolGuid
,
517 This
->DriverBindingHandle
,
519 EFI_OPEN_PROTOCOL_GET_PROTOCOL
521 if (EFI_ERROR (Status
)) {
525 Status
= gBS
->OpenProtocol (
527 &gEfiSimpleTextInputExProtocolGuid
,
529 This
->DriverBindingHandle
,
531 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
533 if (EFI_ERROR (Status
)) {
537 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
540 // Report that the keyboard is being disabled
542 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
544 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
545 ConsoleIn
->DevicePath
548 if (ConsoleIn
->TimerEvent
!= NULL
) {
549 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
550 ConsoleIn
->TimerEvent
= NULL
;
554 // Since there will be no timer handler for keyboard input any more,
555 // exhaust input data just in case there is still keyboard data left
557 Status
= EFI_SUCCESS
;
558 while (!EFI_ERROR (Status
)) {
559 Status
= KeyboardRead (ConsoleIn
, &Data
);
563 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
565 Status
= gBS
->UninstallMultipleProtocolInterfaces (
567 &gEfiSimpleTextInProtocolGuid
,
569 &gEfiSimpleTextInputExProtocolGuid
,
573 if (EFI_ERROR (Status
)) {
579 &gEfiSioProtocolGuid
,
580 This
->DriverBindingHandle
,
585 // Free other resources
587 if ((ConsoleIn
->ConIn
).WaitForKey
!= NULL
) {
588 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
589 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
592 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
593 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
594 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
597 if (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
) {
598 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
599 ConsoleIn
->KeyNotifyProcessEvent
= NULL
;
602 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
603 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
604 gBS
->FreePool (ConsoleIn
);
610 Free the waiting key notify list.
612 @param ListHead Pointer to list head
614 @retval EFI_INVALID_PARAMETER ListHead is NULL
615 @retval EFI_SUCCESS Success to free NotifyList
619 IN OUT LIST_ENTRY
*ListHead
622 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
624 if (ListHead
== NULL
) {
625 return EFI_INVALID_PARAMETER
;
628 while (!IsListEmpty (ListHead
)) {
630 ListHead
->ForwardLink
,
631 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
633 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
635 RemoveEntryList (ListHead
->ForwardLink
);
636 gBS
->FreePool (NotifyNode
);
643 The module Entry Point for module Ps2Keyboard.
645 @param[in] ImageHandle The firmware allocated handle for the EFI image.
646 @param[in] SystemTable A pointer to the EFI System Table.
648 @retval EFI_SUCCESS The entry point is executed successfully.
649 @retval other Some error occurs when executing this entry point.
654 InitializePs2Keyboard (
655 IN EFI_HANDLE ImageHandle
,
656 IN EFI_SYSTEM_TABLE
*SystemTable
662 // Install driver model protocol(s).
664 Status
= EfiLibInstallDriverBindingComponentName2 (
667 &gKeyboardControllerDriver
,
669 &gPs2KeyboardComponentName
,
670 &gPs2KeyboardComponentName2
672 ASSERT_EFI_ERROR (Status
);