3 PS/2 Keyboard driver. Routines that interacts with callers,
4 conforming to EFI driver model
6 Copyright (c) 2006 - 2007, Intel Corporation
7 All rights reserved. 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
24 KbdControllerDriverSupported (
25 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
26 IN EFI_HANDLE Controller
,
27 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
32 KbdControllerDriverStart (
33 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
34 IN EFI_HANDLE Controller
,
35 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
40 KbdControllerDriverStop (
41 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
42 IN EFI_HANDLE Controller
,
43 IN UINTN NumberOfChildren
,
44 IN EFI_HANDLE
*ChildHandleBuffer
49 IN OUT LIST_ENTRY
*ListHead
53 // DriverBinding Protocol Instance
55 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver
= {
56 KbdControllerDriverSupported
,
57 KbdControllerDriverStart
,
58 KbdControllerDriverStop
,
65 Test controller is a keyboard Controller
67 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
68 @param Controller driver's controller
69 @param RemainingDevicePath children device path
71 @retval EFI_UNSUPPORTED controller is not floppy disk
72 @retval EFI_SUCCESS controller is floppy disk
76 KbdControllerDriverSupported (
77 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
78 IN EFI_HANDLE Controller
,
79 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
83 EFI_ISA_IO_PROTOCOL
*IsaIo
;
86 // Open the IO Abstraction(s) needed to perform the supported test
88 Status
= gBS
->OpenProtocol (
90 &gEfiIsaIoProtocolGuid
,
92 This
->DriverBindingHandle
,
94 EFI_OPEN_PROTOCOL_BY_DRIVER
96 if (EFI_ERROR (Status
)) {
100 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
102 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
103 Status
= EFI_UNSUPPORTED
;
106 // Close the I/O Abstraction(s) used to perform the supported test
110 &gEfiIsaIoProtocolGuid
,
111 This
->DriverBindingHandle
,
119 Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
121 @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
122 @param Controller driver controller handle
123 @param RemainingDevicePath Children's device path
125 @retval whether success to create floppy control instance.
129 KbdControllerDriverStart (
130 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
131 IN EFI_HANDLE Controller
,
132 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
137 EFI_ISA_IO_PROTOCOL
*IsaIo
;
138 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
140 EFI_STATUS_CODE_VALUE StatusCode
;
141 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
145 Status
= gBS
->OpenProtocol (
147 &gEfiDevicePathProtocolGuid
,
148 (VOID
**) &ParentDevicePath
,
149 This
->DriverBindingHandle
,
151 EFI_OPEN_PROTOCOL_BY_DRIVER
153 if (EFI_ERROR (Status
)) {
157 // Report that the keyboard is being enabled
159 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
161 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
166 // Get the ISA I/O Protocol on Controller's handle
168 Status
= gBS
->OpenProtocol (
170 &gEfiIsaIoProtocolGuid
,
172 This
->DriverBindingHandle
,
174 EFI_OPEN_PROTOCOL_BY_DRIVER
176 if (EFI_ERROR (Status
)) {
179 &gEfiDevicePathProtocolGuid
,
180 This
->DriverBindingHandle
,
183 return EFI_INVALID_PARAMETER
;
186 // Allocate private data
188 ConsoleIn
= AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV
));
189 if (ConsoleIn
== NULL
) {
190 Status
= EFI_OUT_OF_RESOURCES
;
191 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
195 // Setup the device instance
197 ConsoleIn
->Signature
= KEYBOARD_CONSOLE_IN_DEV_SIGNATURE
;
198 ConsoleIn
->Handle
= Controller
;
199 (ConsoleIn
->ConIn
).Reset
= KeyboardEfiReset
;
200 (ConsoleIn
->ConIn
).ReadKeyStroke
= KeyboardReadKeyStroke
;
201 ConsoleIn
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
202 ConsoleIn
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
203 ConsoleIn
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
204 ConsoleIn
->IsaIo
= IsaIo
;
205 ConsoleIn
->ScancodeBufStartPos
= 0;
206 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
207 ConsoleIn
->ScancodeBufCount
= 0;
208 ConsoleIn
->Ctrled
= FALSE
;
209 ConsoleIn
->Alted
= FALSE
;
210 ConsoleIn
->DevicePath
= ParentDevicePath
;
212 ConsoleIn
->ConInEx
.Reset
= KeyboardEfiResetEx
;
213 ConsoleIn
->ConInEx
.ReadKeyStrokeEx
= KeyboardReadKeyStrokeEx
;
214 ConsoleIn
->ConInEx
.SetState
= KeyboardSetState
;
215 ConsoleIn
->ConInEx
.RegisterKeyNotify
= KeyboardRegisterKeyNotify
;
216 ConsoleIn
->ConInEx
.UnregisterKeyNotify
= KeyboardUnregisterKeyNotify
;
218 InitializeListHead (&ConsoleIn
->NotifyList
);
221 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
223 KeyboardRead (ConsoleIn
, &Data
);
224 if ((KeyReadStatusRegister (ConsoleIn
) & (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
226 // If nobody decodes KBC I/O port, it will read back as 0xFF.
227 // Check the Time-Out and Parity bit to see if it has an active KBC in system
229 Status
= EFI_DEVICE_ERROR
;
230 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
235 // Setup the WaitForKey event
237 Status
= gBS
->CreateEvent (
242 &((ConsoleIn
->ConIn
).WaitForKey
)
244 if (EFI_ERROR (Status
)) {
245 Status
= EFI_OUT_OF_RESOURCES
;
246 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
250 // Setup the WaitForKeyEx event
252 Status
= gBS
->CreateEvent (
255 KeyboardWaitForKeyEx
,
256 &(ConsoleIn
->ConInEx
),
257 &(ConsoleIn
->ConInEx
.WaitForKeyEx
)
259 if (EFI_ERROR (Status
)) {
260 Status
= EFI_OUT_OF_RESOURCES
;
261 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
264 // Setup a periodic timer, used for reading keystrokes at a fixed interval
266 Status
= gBS
->CreateEvent (
267 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
269 KeyboardTimerHandler
,
271 &ConsoleIn
->TimerEvent
273 if (EFI_ERROR (Status
)) {
274 Status
= EFI_OUT_OF_RESOURCES
;
275 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
279 Status
= gBS
->SetTimer (
280 ConsoleIn
->TimerEvent
,
282 KEYBOARD_TIMER_INTERVAL
284 if (EFI_ERROR (Status
)) {
285 Status
= EFI_OUT_OF_RESOURCES
;
286 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
290 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
292 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
297 // Reset the keyboard device
299 Status
= ConsoleIn
->ConIn
.Reset (&ConsoleIn
->ConIn
, TRUE
);
300 if (EFI_ERROR (Status
)) {
301 Status
= EFI_DEVICE_ERROR
;
302 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
306 ConsoleIn
->ControllerNameTable
= NULL
;
309 gPs2KeyboardComponentName
.SupportedLanguages
,
310 &ConsoleIn
->ControllerNameTable
,
311 L
"PS/2 Keyboard Device",
316 gPs2KeyboardComponentName2
.SupportedLanguages
,
317 &ConsoleIn
->ControllerNameTable
,
318 L
"PS/2 Keyboard Device",
324 // Install protocol interfaces for the keyboard device.
326 Status
= gBS
->InstallMultipleProtocolInterfaces (
328 &gEfiSimpleTextInProtocolGuid
,
330 &gEfiSimpleTextInputExProtocolGuid
,
334 if (EFI_ERROR (Status
)) {
335 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
345 if (StatusCode
!= 0) {
346 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
347 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
353 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConIn
.WaitForKey
!= NULL
)) {
354 gBS
->CloseEvent (ConsoleIn
->ConIn
.WaitForKey
);
357 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->TimerEvent
!= NULL
)) {
358 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
360 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
)) {
361 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
363 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
364 if ((ConsoleIn
!= NULL
) && (ConsoleIn
->ControllerNameTable
!= NULL
)) {
365 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
368 // Since there will be no timer handler for keyboard input any more,
369 // exhaust input data just in case there is still keyboard data left
371 if (ConsoleIn
!= NULL
) {
372 Status1
= EFI_SUCCESS
;
373 while (!EFI_ERROR (Status1
) && (Status
!= EFI_DEVICE_ERROR
)) {
374 Status1
= KeyboardRead (ConsoleIn
, &Data
);;
378 if (ConsoleIn
!= NULL
) {
379 gBS
->FreePool (ConsoleIn
);
384 &gEfiDevicePathProtocolGuid
,
385 This
->DriverBindingHandle
,
391 &gEfiIsaIoProtocolGuid
,
392 This
->DriverBindingHandle
,
400 Stop this driver on ControllerHandle. Support stoping any child handles
401 created by this driver.
403 @param This Protocol instance pointer.
404 @param ControllerHandle Handle of device to stop driver on
405 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
406 children is zero stop the entire bus driver.
407 @param ChildHandleBuffer List of Child Handles to Stop.
409 @retval EFI_SUCCESS This driver is removed ControllerHandle
410 @retval other This driver was not removed from this device
415 KbdControllerDriverStop (
416 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
417 IN EFI_HANDLE Controller
,
418 IN UINTN NumberOfChildren
,
419 IN EFI_HANDLE
*ChildHandleBuffer
423 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*ConIn
;
424 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
430 Status
= gBS
->OpenProtocol (
432 &gEfiSimpleTextInProtocolGuid
,
434 This
->DriverBindingHandle
,
436 EFI_OPEN_PROTOCOL_GET_PROTOCOL
438 if (EFI_ERROR (Status
)) {
441 Status
= gBS
->OpenProtocol (
443 &gEfiSimpleTextInputExProtocolGuid
,
445 This
->DriverBindingHandle
,
447 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
449 if (EFI_ERROR (Status
)) {
453 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn
);
456 // Report that the keyboard is being disabled
458 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
460 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_DISABLE
,
461 ConsoleIn
->DevicePath
464 if (ConsoleIn
->TimerEvent
) {
465 gBS
->CloseEvent (ConsoleIn
->TimerEvent
);
466 ConsoleIn
->TimerEvent
= NULL
;
469 // Disable the keyboard interface
471 Status
= DisableKeyboard (ConsoleIn
);
474 // Since there will be no timer handler for keyboard input any more,
475 // exhaust input data just in case there is still keyboard data left
477 Status
= EFI_SUCCESS
;
478 while (!EFI_ERROR (Status
)) {
479 Status
= KeyboardRead (ConsoleIn
, &Data
);;
482 // Uninstall the SimpleTextIn and SimpleTextInEx protocols
484 Status
= gBS
->UninstallMultipleProtocolInterfaces (
486 &gEfiSimpleTextInProtocolGuid
,
488 &gEfiSimpleTextInputExProtocolGuid
,
492 if (EFI_ERROR (Status
)) {
498 &gEfiDevicePathProtocolGuid
,
499 This
->DriverBindingHandle
,
505 &gEfiIsaIoProtocolGuid
,
506 This
->DriverBindingHandle
,
511 // Free other resources
513 if ((ConsoleIn
->ConIn
).WaitForKey
) {
514 gBS
->CloseEvent ((ConsoleIn
->ConIn
).WaitForKey
);
515 (ConsoleIn
->ConIn
).WaitForKey
= NULL
;
517 if (ConsoleIn
->ConInEx
.WaitForKeyEx
!= NULL
) {
518 gBS
->CloseEvent (ConsoleIn
->ConInEx
.WaitForKeyEx
);
519 ConsoleIn
->ConInEx
.WaitForKeyEx
= NULL
;
521 KbdFreeNotifyList (&ConsoleIn
->NotifyList
);
522 FreeUnicodeStringTable (ConsoleIn
->ControllerNameTable
);
523 gBS
->FreePool (ConsoleIn
);
529 Free the waiting key notify list.
531 @param ListHead Pointer to list head
535 IN OUT LIST_ENTRY
*ListHead
538 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
540 if (ListHead
== NULL
) {
541 return EFI_INVALID_PARAMETER
;
543 while (!IsListEmpty (ListHead
)) {
545 ListHead
->ForwardLink
,
546 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
548 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
550 RemoveEntryList (ListHead
->ForwardLink
);
551 gBS
->FreePool (NotifyNode
);
558 The user Entry Point for module Ps2Keyboard. The user code starts with this function.
560 @param[in] ImageHandle The firmware allocated handle for the EFI image.
561 @param[in] SystemTable A pointer to the EFI System Table.
563 @retval EFI_SUCCESS The entry point is executed successfully.
564 @retval other Some error occurs when executing this entry point.
569 InitializePs2Keyboard(
570 IN EFI_HANDLE ImageHandle
,
571 IN EFI_SYSTEM_TABLE
*SystemTable
577 // Install driver model protocol(s).
579 Status
= EfiLibInstallDriverBindingComponentName2 (
582 &gKeyboardControllerDriver
,
584 &gPs2KeyboardComponentName
,
585 &gPs2KeyboardComponentName2
587 ASSERT_EFI_ERROR (Status
);