3 PS/2 Keyboard driver. Routines that interacts with callers,
4 conforming to EFI driver model
6 Copyright (c) 2006 - 2018, 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_ISA_IO_PROTOCOL
*IsaIo
;
121 // Open the IO Abstraction(s) needed to perform the supported test
123 Status
= gBS
->OpenProtocol (
125 &gEfiIsaIoProtocolGuid
,
127 This
->DriverBindingHandle
,
129 EFI_OPEN_PROTOCOL_BY_DRIVER
131 if (EFI_ERROR (Status
)) {
135 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
137 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
138 Status
= EFI_UNSUPPORTED
;
141 // Close the I/O Abstraction(s) used to perform the supported test
145 &gEfiIsaIoProtocolGuid
,
146 This
->DriverBindingHandle
,
154 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
156 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
157 @param Controller driver controller handle
158 @param RemainingDevicePath Children's device path
160 @retval whether success to create floppy control instance.
164 KbdControllerDriverStart (
165 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
166 IN EFI_HANDLE Controller
,
167 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
172 EFI_ISA_IO_PROTOCOL
*IsaIo
;
173 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
175 EFI_STATUS_CODE_VALUE StatusCode
;
176 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
180 Status
= gBS
->OpenProtocol (
182 &gEfiDevicePathProtocolGuid
,
183 (VOID
**) &ParentDevicePath
,
184 This
->DriverBindingHandle
,
186 EFI_OPEN_PROTOCOL_BY_DRIVER
188 if (EFI_ERROR (Status
)) {
192 // Report that the keyboard is being enabled
194 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
196 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
201 // Get the ISA I/O Protocol on Controller's handle
203 Status
= gBS
->OpenProtocol (
205 &gEfiIsaIoProtocolGuid
,
207 This
->DriverBindingHandle
,
209 EFI_OPEN_PROTOCOL_BY_DRIVER
211 if (EFI_ERROR (Status
)) {
214 &gEfiDevicePathProtocolGuid
,
215 This
->DriverBindingHandle
,
218 return EFI_INVALID_PARAMETER
;
221 // Allocate private data
223 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
224 if (ConsoleIn
== NULL
) {
225 Status
= EFI_OUT_OF_RESOURCES
;
226 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
230 // Setup the device instance
232 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
233 ConsoleIn
->Handle
= Controller
;
234 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
235 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
236 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
237 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
238 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
239 ConsoleIn
->IsaIo
= IsaIo
;
240 ConsoleIn
->DevicePath
= ParentDevicePath
;
242 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
243 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
244 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
245 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
246 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
248 InitializeListHead (&ConsoleIn
->NotifyList
);
251 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
252 // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
253 // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
254 // So instead we read status register to detect after read if KBC decode is enabled.
258 // Return code is ignored on purpose.
260 if (!PcdGetBool (PcdFastPS2Detection
)) {
261 KeyboardRead (ConsoleIn
, &Data
);
262 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
264 // If nobody decodes KBC I/O port, it will read back as 0xFF.
265 // Check the Time-Out and Parity bit to see if it has an active KBC in system
267 Status
= EFI_DEVICE_ERROR
;
268 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
274 // Setup the WaitForKey event
276 Status
= gBS
->CreateEvent (
281 &((ConsoleIn
->ConIn
).WaitForKey
)
283 if (EFI_ERROR (Status
)) {
284 Status
= EFI_OUT_OF_RESOURCES
;
285 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
289 // Setup the WaitForKeyEx event
291 Status
= gBS
->CreateEvent (
294 KeyboardWaitForKeyEx
,
296 &(ConsoleIn
->ConInEx
.WaitForKeyEx
)
298 if (EFI_ERROR (Status
)) {
299 Status
= EFI_OUT_OF_RESOURCES
;
300 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
304 // Setup a periodic timer, used for reading keystrokes at a fixed interval
306 Status
= gBS
->CreateEvent (
307 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
309 KeyboardTimerHandler
,
311 &ConsoleIn
->TimerEvent
313 if (EFI_ERROR (Status
)) {
314 Status
= EFI_OUT_OF_RESOURCES
;
315 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
319 Status
= gBS
->SetTimer (
320 ConsoleIn
->TimerEvent
,
322 KEYBOARD_TIMER_INTERVAL
324 if (EFI_ERROR (Status
)) {
325 Status
= EFI_OUT_OF_RESOURCES
;
326 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
330 Status
= gBS
->CreateEvent (
333 KeyNotifyProcessHandler
,
335 &ConsoleIn
->KeyNotifyProcessEvent
337 if (EFI_ERROR (Status
)) {
338 Status
= EFI_OUT_OF_RESOURCES
;
339 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
343 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
345 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
350 // Reset the keyboard device
352 Status
= ConsoleIn
->ConInEx
.Reset (&ConsoleIn
->ConInEx
, FeaturePcdGet (PcdPs2KbdExtendedVerification
));
353 if (EFI_ERROR (Status
)) {
354 Status
= EFI_DEVICE_ERROR
;
355 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
359 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
361 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DETECTED
,
365 ConsoleIn
->ControllerNameTable
= NULL
;
368 gPs2KeyboardComponentName
.SupportedLanguages
,
369 &ConsoleIn
->ControllerNameTable
,
370 L
"PS/2 Keyboard Device",
375 gPs2KeyboardComponentName2
.SupportedLanguages
,
376 &ConsoleIn
->ControllerNameTable
,
377 L
"PS/2 Keyboard Device",
383 // Install protocol interfaces for the keyboard device.
385 Status
= gBS
->InstallMultipleProtocolInterfaces (
387 &gEfiSimpleTextInProtocolGuid
,
389 &gEfiSimpleTextInputExProtocolGuid
,
393 if (EFI_ERROR (Status
)) {
394 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
404 if (StatusCode
!= 0) {
405 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
406 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
412 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConIn
.WaitForKey
!= NULL
)) {
413 gBS
->CloseEvent (ConsoleIn
->ConIn
.WaitForKey
);
416 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->TimerEvent
!= NULL
)) {
417 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
419 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
420 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
422 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
)) {
423 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
425 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
426 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
427 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
430 // Since there will be no timer handler for keyboard input any more,
431 // exhaust input data just in case there is still keyboard data left
433 if (ConsoleIn
!= NULL
) {
434 Status1
= EFI_SUCCESS
;
435 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
436 Status1
= KeyboardRead (ConsoleIn
, &Data
);;
440 if (ConsoleIn
!= NULL
) {
441 gBS
->FreePool (ConsoleIn
);
446 &gEfiDevicePathProtocolGuid
,
447 This
->DriverBindingHandle
,
453 &gEfiIsaIoProtocolGuid
,
454 This
->DriverBindingHandle
,
462 Stop this driver on ControllerHandle. Support stopping any child handles
463 created by this driver.
465 @param This Protocol instance pointer.
466 @param ControllerHandle Handle of device to stop driver on
467 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
468 children is zero stop the entire bus driver.
469 @param ChildHandleBuffer List of Child Handles to Stop.
471 @retval EFI_SUCCESS This driver is removed ControllerHandle
472 @retval other This driver was not removed from this device
477 KbdControllerDriverStop (
478 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
479 IN EFI_HANDLE Controller
,
480 IN UINTN NumberOfChildren
,
481 IN EFI_HANDLE
*ChildHandleBuffer
485 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
486 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
492 Status
= gBS
->OpenProtocol (
494 &gEfiSimpleTextInProtocolGuid
,
496 This
->DriverBindingHandle
,
498 EFI_OPEN_PROTOCOL_GET_PROTOCOL
500 if (EFI_ERROR (Status
)) {
503 Status
= gBS
->OpenProtocol (
505 &gEfiSimpleTextInputExProtocolGuid
,
507 This
->DriverBindingHandle
,
509 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
511 if (EFI_ERROR (Status
)) {
515 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
518 // Report that the keyboard is being disabled
520 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
522 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
523 ConsoleIn
->DevicePath
526 if (ConsoleIn
->TimerEvent
!= NULL
) {
527 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
528 ConsoleIn
->TimerEvent
= NULL
;
532 // Since there will be no timer handler for keyboard input any more,
533 // exhaust input data just in case there is still keyboard data left
535 Status
= EFI_SUCCESS
;
536 while (!EFI_ERROR (Status
)) {
537 Status
= KeyboardRead (ConsoleIn
, &Data
);;
540 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
542 Status
= gBS
->UninstallMultipleProtocolInterfaces (
544 &gEfiSimpleTextInProtocolGuid
,
546 &gEfiSimpleTextInputExProtocolGuid
,
550 if (EFI_ERROR (Status
)) {
556 &gEfiDevicePathProtocolGuid
,
557 This
->DriverBindingHandle
,
563 &gEfiIsaIoProtocolGuid
,
564 This
->DriverBindingHandle
,
569 // Free other resources
571 if ((ConsoleIn
->ConIn
).WaitForKey
!= NULL
) {
572 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
573 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
575 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
576 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
577 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
579 if (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
) {
580 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
581 ConsoleIn
->KeyNotifyProcessEvent
= NULL
;
583 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
584 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
585 gBS
->FreePool (ConsoleIn
);
591 Free the waiting key notify list.
593 @param ListHead Pointer to list head
595 @retval EFI_INVALID_PARAMETER ListHead is NULL
596 @retval EFI_SUCCESS Sucess to free NotifyList
600 IN OUT LIST_ENTRY
*ListHead
603 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
605 if (ListHead
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
608 while (!IsListEmpty (ListHead
)) {
610 ListHead
->ForwardLink
,
611 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
613 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
615 RemoveEntryList (ListHead
->ForwardLink
);
616 gBS
->FreePool (NotifyNode
);
623 The module Entry Point for module Ps2Keyboard.
625 @param[in] ImageHandle The firmware allocated handle for the EFI image.
626 @param[in] SystemTable A pointer to the EFI System Table.
628 @retval EFI_SUCCESS The entry point is executed successfully.
629 @retval other Some error occurs when executing this entry point.
634 InitializePs2Keyboard(
635 IN EFI_HANDLE ImageHandle
,
636 IN EFI_SYSTEM_TABLE
*SystemTable
642 // Install driver model protocol(s).
644 Status
= EfiLibInstallDriverBindingComponentName2 (
647 &gKeyboardControllerDriver
,
649 &gPs2KeyboardComponentName
,
650 &gPs2KeyboardComponentName2
652 ASSERT_EFI_ERROR (Status
);