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_ISA_IO_PROTOCOL
*IsaIo
;
127 // Open the IO Abstraction(s) needed to perform the supported test
129 Status
= gBS
->OpenProtocol (
131 &gEfiIsaIoProtocolGuid
,
133 This
->DriverBindingHandle
,
135 EFI_OPEN_PROTOCOL_BY_DRIVER
137 if (EFI_ERROR (Status
)) {
141 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
143 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
144 Status
= EFI_UNSUPPORTED
;
147 // Close the I/O Abstraction(s) used to perform the supported test
151 &gEfiIsaIoProtocolGuid
,
152 This
->DriverBindingHandle
,
160 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
162 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
163 @param Controller driver controller handle
164 @param RemainingDevicePath Children's device path
166 @retval whether success to create floppy control instance.
170 KbdControllerDriverStart (
171 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
172 IN EFI_HANDLE Controller
,
173 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
178 EFI_ISA_IO_PROTOCOL
*IsaIo
;
179 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
181 EFI_STATUS_CODE_VALUE StatusCode
;
182 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
186 Status
= gBS
->OpenProtocol (
188 &gEfiDevicePathProtocolGuid
,
189 (VOID
**) &ParentDevicePath
,
190 This
->DriverBindingHandle
,
192 EFI_OPEN_PROTOCOL_BY_DRIVER
194 if (EFI_ERROR (Status
)) {
198 // Report that the keyboard is being enabled
200 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
202 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
207 // Get the ISA I/O Protocol on Controller's handle
209 Status
= gBS
->OpenProtocol (
211 &gEfiIsaIoProtocolGuid
,
213 This
->DriverBindingHandle
,
215 EFI_OPEN_PROTOCOL_BY_DRIVER
217 if (EFI_ERROR (Status
)) {
220 &gEfiDevicePathProtocolGuid
,
221 This
->DriverBindingHandle
,
224 return EFI_INVALID_PARAMETER
;
227 // Allocate private data
229 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
230 if (ConsoleIn
== NULL
) {
231 Status
= EFI_OUT_OF_RESOURCES
;
232 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
236 // Setup the device instance
238 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
239 ConsoleIn
->Handle
= Controller
;
240 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
241 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
242 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
243 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
244 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
245 ConsoleIn
->IsaIo
= IsaIo
;
246 ConsoleIn
->DevicePath
= ParentDevicePath
;
248 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
249 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
250 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
251 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
252 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
254 InitializeListHead (&ConsoleIn
->NotifyList
);
257 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
258 // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
259 // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
260 // So instead we read status register to detect after read if KBC decode is enabled.
264 // Return code is ignored on purpose.
266 if (!PcdGetBool (PcdFastPS2Detection
)) {
267 KeyboardRead (ConsoleIn
, &Data
);
268 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
270 // If nobody decodes KBC I/O port, it will read back as 0xFF.
271 // Check the Time-Out and Parity bit to see if it has an active KBC in system
273 Status
= EFI_DEVICE_ERROR
;
274 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
280 // Setup the WaitForKey event
282 Status
= gBS
->CreateEvent (
287 &((ConsoleIn
->ConIn
).WaitForKey
)
289 if (EFI_ERROR (Status
)) {
290 Status
= EFI_OUT_OF_RESOURCES
;
291 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
295 // Setup the WaitForKeyEx event
297 Status
= gBS
->CreateEvent (
300 KeyboardWaitForKeyEx
,
302 &(ConsoleIn
->ConInEx
.WaitForKeyEx
)
304 if (EFI_ERROR (Status
)) {
305 Status
= EFI_OUT_OF_RESOURCES
;
306 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
310 // Setup a periodic timer, used for reading keystrokes at a fixed interval
312 Status
= gBS
->CreateEvent (
313 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
315 KeyboardTimerHandler
,
317 &ConsoleIn
->TimerEvent
319 if (EFI_ERROR (Status
)) {
320 Status
= EFI_OUT_OF_RESOURCES
;
321 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
325 Status
= gBS
->SetTimer (
326 ConsoleIn
->TimerEvent
,
328 KEYBOARD_TIMER_INTERVAL
330 if (EFI_ERROR (Status
)) {
331 Status
= EFI_OUT_OF_RESOURCES
;
332 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
336 Status
= gBS
->CreateEvent (
339 KeyNotifyProcessHandler
,
341 &ConsoleIn
->KeyNotifyProcessEvent
343 if (EFI_ERROR (Status
)) {
344 Status
= EFI_OUT_OF_RESOURCES
;
345 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
349 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
351 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
356 // Reset the keyboard device
358 Status
= ConsoleIn
->ConInEx
.Reset (&ConsoleIn
->ConInEx
, FeaturePcdGet (PcdPs2KbdExtendedVerification
));
359 if (EFI_ERROR (Status
)) {
360 Status
= EFI_DEVICE_ERROR
;
361 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
365 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
367 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DETECTED
,
371 ConsoleIn
->ControllerNameTable
= NULL
;
374 gPs2KeyboardComponentName
.SupportedLanguages
,
375 &ConsoleIn
->ControllerNameTable
,
376 L
"PS/2 Keyboard Device",
381 gPs2KeyboardComponentName2
.SupportedLanguages
,
382 &ConsoleIn
->ControllerNameTable
,
383 L
"PS/2 Keyboard Device",
389 // Install protocol interfaces for the keyboard device.
391 Status
= gBS
->InstallMultipleProtocolInterfaces (
393 &gEfiSimpleTextInProtocolGuid
,
395 &gEfiSimpleTextInputExProtocolGuid
,
399 if (EFI_ERROR (Status
)) {
400 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
410 if (StatusCode
!= 0) {
411 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
412 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
418 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConIn
.WaitForKey
!= NULL
)) {
419 gBS
->CloseEvent (ConsoleIn
->ConIn
.WaitForKey
);
422 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->TimerEvent
!= NULL
)) {
423 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
425 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
426 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
428 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
)) {
429 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
431 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
432 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
433 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
436 // Since there will be no timer handler for keyboard input any more,
437 // exhaust input data just in case there is still keyboard data left
439 if (ConsoleIn
!= NULL
) {
440 Status1
= EFI_SUCCESS
;
441 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
442 Status1
= KeyboardRead (ConsoleIn
, &Data
);;
446 if (ConsoleIn
!= NULL
) {
447 gBS
->FreePool (ConsoleIn
);
452 &gEfiDevicePathProtocolGuid
,
453 This
->DriverBindingHandle
,
459 &gEfiIsaIoProtocolGuid
,
460 This
->DriverBindingHandle
,
468 Stop this driver on ControllerHandle. Support stopping any child handles
469 created by this driver.
471 @param This Protocol instance pointer.
472 @param ControllerHandle Handle of device to stop driver on
473 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
474 children is zero stop the entire bus driver.
475 @param ChildHandleBuffer List of Child Handles to Stop.
477 @retval EFI_SUCCESS This driver is removed ControllerHandle
478 @retval other This driver was not removed from this device
483 KbdControllerDriverStop (
484 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
485 IN EFI_HANDLE Controller
,
486 IN UINTN NumberOfChildren
,
487 IN EFI_HANDLE
*ChildHandleBuffer
491 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
492 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
498 Status
= gBS
->OpenProtocol (
500 &gEfiSimpleTextInProtocolGuid
,
502 This
->DriverBindingHandle
,
504 EFI_OPEN_PROTOCOL_GET_PROTOCOL
506 if (EFI_ERROR (Status
)) {
509 Status
= gBS
->OpenProtocol (
511 &gEfiSimpleTextInputExProtocolGuid
,
513 This
->DriverBindingHandle
,
515 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
517 if (EFI_ERROR (Status
)) {
521 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
524 // Report that the keyboard is being disabled
526 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
528 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
529 ConsoleIn
->DevicePath
532 if (ConsoleIn
->TimerEvent
!= NULL
) {
533 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
534 ConsoleIn
->TimerEvent
= NULL
;
538 // Since there will be no timer handler for keyboard input any more,
539 // exhaust input data just in case there is still keyboard data left
541 Status
= EFI_SUCCESS
;
542 while (!EFI_ERROR (Status
)) {
543 Status
= KeyboardRead (ConsoleIn
, &Data
);;
546 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
548 Status
= gBS
->UninstallMultipleProtocolInterfaces (
550 &gEfiSimpleTextInProtocolGuid
,
552 &gEfiSimpleTextInputExProtocolGuid
,
556 if (EFI_ERROR (Status
)) {
562 &gEfiDevicePathProtocolGuid
,
563 This
->DriverBindingHandle
,
569 &gEfiIsaIoProtocolGuid
,
570 This
->DriverBindingHandle
,
575 // Free other resources
577 if ((ConsoleIn
->ConIn
).WaitForKey
!= NULL
) {
578 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
579 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
581 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
582 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
583 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
585 if (ConsoleIn
->KeyNotifyProcessEvent
!= NULL
) {
586 gBS
->CloseEvent (ConsoleIn
->KeyNotifyProcessEvent
);
587 ConsoleIn
->KeyNotifyProcessEvent
= NULL
;
589 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
590 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
591 gBS
->FreePool (ConsoleIn
);
597 Free the waiting key notify list.
599 @param ListHead Pointer to list head
601 @retval EFI_INVALID_PARAMETER ListHead is NULL
602 @retval EFI_SUCCESS Sucess to free NotifyList
606 IN OUT LIST_ENTRY
*ListHead
609 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
611 if (ListHead
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
614 while (!IsListEmpty (ListHead
)) {
616 ListHead
->ForwardLink
,
617 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
619 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
621 RemoveEntryList (ListHead
->ForwardLink
);
622 gBS
->FreePool (NotifyNode
);
629 The module Entry Point for module Ps2Keyboard.
631 @param[in] ImageHandle The firmware allocated handle for the EFI image.
632 @param[in] SystemTable A pointer to the EFI System Table.
634 @retval EFI_SUCCESS The entry point is executed successfully.
635 @retval other Some error occurs when executing this entry point.
640 InitializePs2Keyboard(
641 IN EFI_HANDLE ImageHandle
,
642 IN EFI_SYSTEM_TABLE
*SystemTable
648 // Install driver model protocol(s).
650 Status
= EfiLibInstallDriverBindingComponentName2 (
653 &gKeyboardControllerDriver
,
655 &gPs2KeyboardComponentName
,
656 &gPs2KeyboardComponentName2
658 ASSERT_EFI_ERROR (Status
);