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 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Ps2Keyboard.h"
20 // Function prototypes
23 Test controller is a keyboard Controller.
25 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
26 @param Controller driver's controller
27 @param RemainingDevicePath children device path
29 @retval EFI_UNSUPPORTED controller is not floppy disk
30 @retval EFI_SUCCESS controller is floppy disk
34 KbdControllerDriverSupported (
35 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
36 IN EFI_HANDLE Controller
,
37 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
41 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
43 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
44 @param Controller driver controller handle
45 @param RemainingDevicePath Children's device path
47 @retval whether success to create floppy control instance.
51 KbdControllerDriverStart (
52 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
53 IN EFI_HANDLE Controller
,
54 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
58 Stop this driver on ControllerHandle. Support stopping any child handles
59 created by this driver.
61 @param This Protocol instance pointer.
62 @param ControllerHandle Handle of device to stop driver on
63 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
64 children is zero stop the entire bus driver.
65 @param ChildHandleBuffer List of Child Handles to Stop.
67 @retval EFI_SUCCESS This driver is removed ControllerHandle
68 @retval other This driver was not removed from this device
73 KbdControllerDriverStop (
74 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
75 IN EFI_HANDLE Controller
,
76 IN UINTN NumberOfChildren
,
77 IN EFI_HANDLE
*ChildHandleBuffer
81 Free the waiting key notify list.
83 @param ListHead Pointer to list head
85 @retval EFI_INVALID_PARAMETER ListHead is NULL
86 @retval EFI_SUCCESS Sucess to free NotifyList
90 IN OUT LIST_ENTRY
*ListHead
94 // DriverBinding Protocol Instance
96 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver
= {
97 KbdControllerDriverSupported
,
98 KbdControllerDriverStart
,
99 KbdControllerDriverStop
,
106 Test controller is a keyboard Controller.
108 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
109 @param Controller driver's controller
110 @param RemainingDevicePath children device path
112 @retval EFI_UNSUPPORTED controller is not floppy disk
113 @retval EFI_SUCCESS controller is floppy disk
117 KbdControllerDriverSupported (
118 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
119 IN EFI_HANDLE Controller
,
120 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
124 EFI_SIO_PROTOCOL
*Sio
;
125 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
126 ACPI_HID_DEVICE_PATH
*Acpi
;
129 // Check whether the controller is keyboard.
131 Status
= gBS
->OpenProtocol (
133 &gEfiDevicePathProtocolGuid
,
134 (VOID
**) &DevicePath
,
135 This
->DriverBindingHandle
,
137 EFI_OPEN_PROTOCOL_GET_PROTOCOL
139 if (EFI_ERROR (Status
)) {
144 Acpi
= (ACPI_HID_DEVICE_PATH
*) DevicePath
;
145 DevicePath
= NextDevicePathNode (DevicePath
);
146 } while (!IsDevicePathEnd (DevicePath
));
148 if (DevicePathType (Acpi
) != ACPI_DEVICE_PATH
||
149 (DevicePathSubType (Acpi
) != ACPI_DP
&& DevicePathSubType (Acpi
) != ACPI_EXTENDED_DP
)) {
150 return EFI_UNSUPPORTED
;
153 if (Acpi
->HID
!= EISA_PNP_ID (0x303) || Acpi
->UID
!= 0) {
154 return EFI_UNSUPPORTED
;
158 // Open the IO Abstraction(s) needed to perform the supported test
160 Status
= gBS
->OpenProtocol (
162 &gEfiSioProtocolGuid
,
164 This
->DriverBindingHandle
,
166 EFI_OPEN_PROTOCOL_BY_DRIVER
168 if (EFI_ERROR (Status
)) {
173 // Close the I/O Abstraction(s) used to perform the supported test
177 &gEfiSioProtocolGuid
,
178 This
->DriverBindingHandle
,
186 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
188 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
189 @param Controller driver controller handle
190 @param RemainingDevicePath Children's device path
192 @retval whether success to create floppy control instance.
196 KbdControllerDriverStart (
197 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
198 IN EFI_HANDLE Controller
,
199 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
204 EFI_SIO_PROTOCOL
*Sio
;
205 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
207 EFI_STATUS_CODE_VALUE StatusCode
;
208 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
212 Status
= gBS
->OpenProtocol (
214 &gEfiDevicePathProtocolGuid
,
215 (VOID
**) &DevicePath
,
216 This
->DriverBindingHandle
,
218 EFI_OPEN_PROTOCOL_GET_PROTOCOL
220 if (EFI_ERROR (Status
)) {
224 // Report that the keyboard is being enabled
226 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
228 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
233 // Get the ISA I/O Protocol on Controller's handle
235 Status
= gBS
->OpenProtocol (
237 &gEfiSioProtocolGuid
,
239 This
->DriverBindingHandle
,
241 EFI_OPEN_PROTOCOL_BY_DRIVER
243 if (EFI_ERROR (Status
)) {
247 // Allocate private data
249 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
250 if (ConsoleIn
== NULL
) {
251 Status
= EFI_OUT_OF_RESOURCES
;
252 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
256 // Setup the device instance
258 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
259 ConsoleIn
->Handle
= Controller
;
260 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
261 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
262 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
263 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
264 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
265 ConsoleIn
->DevicePath
= DevicePath
;
267 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
268 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
269 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
270 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
271 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
273 InitializeListHead (&ConsoleIn
->NotifyList
);
276 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
277 // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
278 // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
279 // So instead we read status register to detect after read if KBC decode is enabled.
283 // Return code is ignored on purpose.
285 if (!PcdGetBool (PcdFastPS2Detection
)) {
286 KeyboardRead (ConsoleIn
, &Data
);
287 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
289 // If nobody decodes KBC I/O port, it will read back as 0xFF.
290 // Check the Time-Out and Parity bit to see if it has an active KBC in system
292 Status
= EFI_DEVICE_ERROR
;
293 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
299 // Setup the WaitForKey event
301 Status
= gBS
->CreateEvent (
306 &((ConsoleIn
->ConIn
).WaitForKey
)
308 if (EFI_ERROR (Status
)) {
309 Status
= EFI_OUT_OF_RESOURCES
;
310 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
;
328 // Setup a periodic timer, used for reading keystrokes at a fixed interval
330 Status
= gBS
->CreateEvent (
331 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
333 KeyboardTimerHandler
,
335 &ConsoleIn
->TimerEvent
337 if (EFI_ERROR (Status
)) {
338 Status
= EFI_OUT_OF_RESOURCES
;
339 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
343 Status
= gBS
->SetTimer (
344 ConsoleIn
->TimerEvent
,
346 KEYBOARD_TIMER_INTERVAL
348 if (EFI_ERROR (Status
)) {
349 Status
= EFI_OUT_OF_RESOURCES
;
350 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
354 Status
= gBS
->CreateEvent (
357 KeyNotifyProcessHandler
,
359 &ConsoleIn
->KeyNotifyProcessEvent
361 if (EFI_ERROR (Status
)) {
362 Status
= EFI_OUT_OF_RESOURCES
;
363 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
367 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
369 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
374 // Reset the keyboard device
376 Status
= ConsoleIn
->ConInEx
.Reset (&ConsoleIn
->ConInEx
, FeaturePcdGet (PcdPs2KbdExtendedVerification
));
377 if (EFI_ERROR (Status
)) {
378 Status
= EFI_DEVICE_ERROR
;
379 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
383 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
385 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DETECTED
,
389 ConsoleIn
->ControllerNameTable
= NULL
;
392 gPs2KeyboardComponentName
.SupportedLanguages
,
393 &ConsoleIn
->ControllerNameTable
,
394 L
"PS/2 Keyboard Device",
399 gPs2KeyboardComponentName2
.SupportedLanguages
,
400 &ConsoleIn
->ControllerNameTable
,
401 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
);
443 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
444 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
446 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
)) {
447 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
449 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
450 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
451 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
454 // Since there will be no timer handler for keyboard input any more,
455 // exhaust input data just in case there is still keyboard data left
457 if (ConsoleIn
!= NULL
) {
458 Status1
= EFI_SUCCESS
;
459 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
460 Status1
= KeyboardRead (ConsoleIn
, &Data
);;
464 if (ConsoleIn
!= NULL
) {
465 gBS
->FreePool (ConsoleIn
);
470 &gEfiSioProtocolGuid
,
471 This
->DriverBindingHandle
,
479 Stop this driver on ControllerHandle. Support stopping any child handles
480 created by this driver.
482 @param This Protocol instance pointer.
483 @param ControllerHandle Handle of device to stop driver on
484 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
485 children is zero stop the entire bus driver.
486 @param ChildHandleBuffer List of Child Handles to Stop.
488 @retval EFI_SUCCESS This driver is removed ControllerHandle
489 @retval other This driver was not removed from this device
494 KbdControllerDriverStop (
495 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
496 IN EFI_HANDLE Controller
,
497 IN UINTN NumberOfChildren
,
498 IN EFI_HANDLE
*ChildHandleBuffer
502 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
503 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
509 Status
= gBS
->OpenProtocol (
511 &gEfiSimpleTextInProtocolGuid
,
513 This
->DriverBindingHandle
,
515 EFI_OPEN_PROTOCOL_GET_PROTOCOL
517 if (EFI_ERROR (Status
)) {
520 Status
= gBS
->OpenProtocol (
522 &gEfiSimpleTextInputExProtocolGuid
,
524 This
->DriverBindingHandle
,
526 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
528 if (EFI_ERROR (Status
)) {
532 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
535 // Report that the keyboard is being disabled
537 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
539 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
540 ConsoleIn
->DevicePath
543 if (ConsoleIn
->TimerEvent
!= NULL
) {
544 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
545 ConsoleIn
->TimerEvent
= NULL
;
549 // Since there will be no timer handler for keyboard input any more,
550 // exhaust input data just in case there is still keyboard data left
552 Status
= EFI_SUCCESS
;
553 while (!EFI_ERROR (Status
)) {
554 Status
= KeyboardRead (ConsoleIn
, &Data
);;
557 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
559 Status
= gBS
->UninstallMultipleProtocolInterfaces (
561 &gEfiSimpleTextInProtocolGuid
,
563 &gEfiSimpleTextInputExProtocolGuid
,
567 if (EFI_ERROR (Status
)) {
573 &gEfiSioProtocolGuid
,
574 This
->DriverBindingHandle
,
579 // Free other resources
581 if ((ConsoleIn
->ConIn
).WaitForKey
!= NULL
) {
582 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
583 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
585 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
586 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
587 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
589 if (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
) {
590 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
591 ConsoleIn
->KeyNotifyProcessEvent
= NULL
;
593 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
594 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
595 gBS
->FreePool (ConsoleIn
);
601 Free the waiting key notify list.
603 @param ListHead Pointer to list head
605 @retval EFI_INVALID_PARAMETER ListHead is NULL
606 @retval EFI_SUCCESS Sucess to free NotifyList
610 IN OUT LIST_ENTRY
*ListHead
613 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
615 if (ListHead
== NULL
) {
616 return EFI_INVALID_PARAMETER
;
618 while (!IsListEmpty (ListHead
)) {
620 ListHead
->ForwardLink
,
621 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
623 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
625 RemoveEntryList (ListHead
->ForwardLink
);
626 gBS
->FreePool (NotifyNode
);
633 The module Entry Point for module Ps2Keyboard.
635 @param[in] ImageHandle The firmware allocated handle for the EFI image.
636 @param[in] SystemTable A pointer to the EFI System Table.
638 @retval EFI_SUCCESS The entry point is executed successfully.
639 @retval other Some error occurs when executing this entry point.
644 InitializePs2Keyboard(
645 IN EFI_HANDLE ImageHandle
,
646 IN EFI_SYSTEM_TABLE
*SystemTable
652 // Install driver model protocol(s).
654 Status
= EfiLibInstallDriverBindingComponentName2 (
657 &gKeyboardControllerDriver
,
659 &gPs2KeyboardComponentName
,
660 &gPs2KeyboardComponentName2
662 ASSERT_EFI_ERROR (Status
);