2 PS/2 Mouse driver. Routines that interacts with callers,
3 conforming to EFI driver model.
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
14 /// DriverBinding Protocol Instance
16 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver
= {
17 PS2MouseDriverSupported
,
26 Test to see if this driver supports ControllerHandle. Any ControllerHandle
27 than contains a IsaIo protocol can be supported.
29 @param This Protocol instance pointer.
30 @param ControllerHandle Handle of device to test
31 @param RemainingDevicePath Optional parameter use to pick a specific child
34 @retval EFI_SUCCESS This driver supports this device
35 @retval EFI_ALREADY_STARTED This driver is already running on this device
36 @retval other This driver does not support this device
41 PS2MouseDriverSupported (
42 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
43 IN EFI_HANDLE Controller
,
44 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
48 EFI_SIO_PROTOCOL
*Sio
;
49 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
50 ACPI_HID_DEVICE_PATH
*Acpi
;
53 // Check whether the controller is keyboard.
55 Status
= gBS
->OpenProtocol (
57 &gEfiDevicePathProtocolGuid
,
59 This
->DriverBindingHandle
,
61 EFI_OPEN_PROTOCOL_GET_PROTOCOL
63 if (EFI_ERROR (Status
)) {
68 Acpi
= (ACPI_HID_DEVICE_PATH
*)DevicePath
;
69 DevicePath
= NextDevicePathNode (DevicePath
);
70 } while (!IsDevicePathEnd (DevicePath
));
72 if ((DevicePathType (Acpi
) != ACPI_DEVICE_PATH
) ||
73 ((DevicePathSubType (Acpi
) != ACPI_DP
) && (DevicePathSubType (Acpi
) != ACPI_EXTENDED_DP
)))
75 return EFI_UNSUPPORTED
;
79 case EISA_PNP_ID (0xF03):
81 // Microsoft PS/2 style mouse
83 case EISA_PNP_ID (0xF13):
85 // PS/2 Port for PS/2-style Mice
89 case EISA_PNP_ID (0x303):
91 // IBM Enhanced (101/102-key, PS/2 mouse support)
98 return EFI_UNSUPPORTED
;
103 // Open the IO Abstraction(s) needed to perform the supported test
105 Status
= gBS
->OpenProtocol (
107 &gEfiSioProtocolGuid
,
109 This
->DriverBindingHandle
,
111 EFI_OPEN_PROTOCOL_BY_DRIVER
113 if (EFI_ERROR (Status
)) {
118 // Close the I/O Abstraction(s) used to perform the supported test
122 &gEfiSioProtocolGuid
,
123 This
->DriverBindingHandle
,
131 Start this driver on ControllerHandle by opening a Sio protocol, creating
132 PS2_MOUSE_DEV device and install gEfiSimplePointerProtocolGuid finally.
134 @param This Protocol instance pointer.
135 @param ControllerHandle Handle of device to bind driver to
136 @param RemainingDevicePath Optional parameter use to pick a specific child
139 @retval EFI_SUCCESS This driver is added to ControllerHandle
140 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
141 @retval other This driver does not support this device
146 PS2MouseDriverStart (
147 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
148 IN EFI_HANDLE Controller
,
149 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
153 EFI_STATUS EmptyStatus
;
154 EFI_SIO_PROTOCOL
*Sio
;
155 PS2_MOUSE_DEV
*MouseDev
;
158 EFI_STATUS_CODE_VALUE StatusCode
;
159 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
164 // Open the device path protocol
166 Status
= gBS
->OpenProtocol (
168 &gEfiDevicePathProtocolGuid
,
169 (VOID
**)&DevicePath
,
170 This
->DriverBindingHandle
,
172 EFI_OPEN_PROTOCOL_GET_PROTOCOL
174 if (EFI_ERROR (Status
)) {
179 // Report that the keyboard is being enabled
181 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
183 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
188 // Get the ISA I/O Protocol on Controller's handle
190 Status
= gBS
->OpenProtocol (
192 &gEfiSioProtocolGuid
,
194 This
->DriverBindingHandle
,
196 EFI_OPEN_PROTOCOL_BY_DRIVER
198 if (EFI_ERROR (Status
)) {
203 // Raise TPL to avoid keyboard operation impact
205 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
208 // Allocate private data
210 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
211 if (MouseDev
== NULL
) {
212 Status
= EFI_OUT_OF_RESOURCES
;
217 // Setup the device instance
219 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
220 MouseDev
->Handle
= Controller
;
221 MouseDev
->SampleRate
= SampleRate20
;
222 MouseDev
->Resolution
= MouseResolution4
;
223 MouseDev
->Scaling
= Scaling1
;
224 MouseDev
->DataPackageSize
= 3;
225 MouseDev
->DevicePath
= DevicePath
;
228 // Resolution = 4 counts/mm
230 MouseDev
->Mode
.ResolutionX
= 4;
231 MouseDev
->Mode
.ResolutionY
= 4;
232 MouseDev
->Mode
.LeftButton
= TRUE
;
233 MouseDev
->Mode
.RightButton
= TRUE
;
235 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
236 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
237 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
240 // Initialize keyboard controller if necessary
242 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
244 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
248 Data
= IoRead8 (KBC_CMD_STS_PORT
);
250 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
252 if ((Data
& (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
254 // If nobody decodes KBC I/O port, it will read back as 0xFF.
255 // Check the Time-Out and Parity bit to see if it has an active KBC in system
257 Status
= EFI_DEVICE_ERROR
;
258 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
262 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
263 Status
= KbcSelfTest ();
264 if (EFI_ERROR (Status
)) {
265 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
272 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
274 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
281 Status
= MouseDev
->SimplePointerProtocol
.Reset (
282 &MouseDev
->SimplePointerProtocol
,
283 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
285 if (EFI_ERROR (Status
)) {
287 // mouse not connected
289 Status
= EFI_SUCCESS
;
290 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
294 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
296 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
301 // Setup the WaitForKey event
303 Status
= gBS
->CreateEvent (
308 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
310 if (EFI_ERROR (Status
)) {
311 Status
= EFI_OUT_OF_RESOURCES
;
316 // Setup a periodic timer, used to poll mouse state
318 Status
= gBS
->CreateEvent (
319 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
323 &MouseDev
->TimerEvent
325 if (EFI_ERROR (Status
)) {
326 Status
= EFI_OUT_OF_RESOURCES
;
331 // Start timer to poll mouse (100 samples per second)
333 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
334 if (EFI_ERROR (Status
)) {
335 Status
= EFI_OUT_OF_RESOURCES
;
339 MouseDev
->ControllerNameTable
= NULL
;
342 gPs2MouseComponentName
.SupportedLanguages
,
343 &MouseDev
->ControllerNameTable
,
344 L
"PS/2 Mouse Device",
349 gPs2MouseComponentName2
.SupportedLanguages
,
350 &MouseDev
->ControllerNameTable
,
351 L
"PS/2 Mouse Device",
356 // Install protocol interfaces for the mouse device.
358 Status
= gBS
->InstallMultipleProtocolInterfaces (
360 &gEfiSimplePointerProtocolGuid
,
361 &MouseDev
->SimplePointerProtocol
,
364 if (EFI_ERROR (Status
)) {
368 gBS
->RestoreTPL (OldTpl
);
374 if (Status
!= EFI_DEVICE_ERROR
) {
378 if (StatusCode
!= 0) {
379 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
380 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
386 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
387 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
390 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
391 gBS
->CloseEvent (MouseDev
->TimerEvent
);
394 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
395 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
398 if (Status
!= EFI_DEVICE_ERROR
) {
400 // Since there will be no timer handler for mouse input any more,
401 // exhaust input data just in case there is still mouse data left
403 EmptyStatus
= EFI_SUCCESS
;
404 while (!EFI_ERROR (EmptyStatus
)) {
405 EmptyStatus
= In8042Data (&Data
);
409 if (MouseDev
!= NULL
) {
415 &gEfiDevicePathProtocolGuid
,
416 This
->DriverBindingHandle
,
422 &gEfiSioProtocolGuid
,
423 This
->DriverBindingHandle
,
427 gBS
->RestoreTPL (OldTpl
);
433 Stop this driver on ControllerHandle. Support stopping any child handles
434 created by this driver.
436 @param This Protocol instance pointer.
437 @param ControllerHandle Handle of device to stop driver on
438 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
439 children is zero stop the entire bus driver.
440 @param ChildHandleBuffer List of Child Handles to Stop.
442 @retval EFI_SUCCESS This driver is removed ControllerHandle
443 @retval other This driver was not removed from this device
449 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
450 IN EFI_HANDLE Controller
,
451 IN UINTN NumberOfChildren
,
452 IN EFI_HANDLE
*ChildHandleBuffer
456 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
457 PS2_MOUSE_DEV
*MouseDev
;
460 Status
= gBS
->OpenProtocol (
462 &gEfiSimplePointerProtocolGuid
,
463 (VOID
**)&SimplePointerProtocol
,
464 This
->DriverBindingHandle
,
466 EFI_OPEN_PROTOCOL_GET_PROTOCOL
468 if (EFI_ERROR (Status
)) {
472 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
475 // Report that the keyboard is being disabled
477 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
479 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
483 Status
= gBS
->UninstallProtocolInterface (
485 &gEfiSimplePointerProtocolGuid
,
486 &MouseDev
->SimplePointerProtocol
488 if (EFI_ERROR (Status
)) {
493 // Cancel mouse data polling timer, close timer event
495 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
496 gBS
->CloseEvent (MouseDev
->TimerEvent
);
499 // Since there will be no timer handler for mouse input any more,
500 // exhaust input data just in case there is still mouse data left
502 Status
= EFI_SUCCESS
;
503 while (!EFI_ERROR (Status
)) {
504 Status
= In8042Data (&Data
);
507 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
508 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
513 &gEfiDevicePathProtocolGuid
,
514 This
->DriverBindingHandle
,
520 &gEfiSioProtocolGuid
,
521 This
->DriverBindingHandle
,
529 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and
530 there is a mouse device connected to system.
532 @param This - Pointer of simple pointer Protocol.
533 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
536 @retval EFI_SUCCESS - The command byte is written successfully.
537 @retval EFI_DEVICE_ERROR - Errors occurred during resetting keyboard.
543 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
544 IN BOOLEAN ExtendedVerification
548 PS2_MOUSE_DEV
*MouseDev
;
550 BOOLEAN KeyboardEnable
;
553 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
556 // Report reset progress code
558 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
560 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
564 KeyboardEnable
= FALSE
;
567 // Raise TPL to avoid keyboard operation impact
569 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
571 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
572 MouseDev
->StateChanged
= FALSE
;
575 // Exhaust input data
577 Status
= EFI_SUCCESS
;
578 while (!EFI_ERROR (Status
)) {
579 Status
= In8042Data (&Data
);
582 CheckKbStatus (&KeyboardEnable
);
587 // if there's data block on KBC data port, read it out
589 if ((IoRead8 (KBC_CMD_STS_PORT
) & KBC_OUTB
) == KBC_OUTB
) {
590 IoRead8 (KBC_DATA_PORT
);
593 Status
= EFI_SUCCESS
;
595 // The PS2 mouse driver reset behavior is always successfully return no matter whether or not there is mouse connected to system.
596 // This behavior is needed by performance speed. The following mouse command only successfully finish when mouse device is
597 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
599 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
601 // Send mouse reset command and set mouse default configure
603 Status
= PS2MouseReset ();
604 if (EFI_ERROR (Status
)) {
605 Status
= EFI_DEVICE_ERROR
;
609 Status
= PS2MouseSetSampleRate (MouseDev
->SampleRate
);
610 if (EFI_ERROR (Status
)) {
611 Status
= EFI_DEVICE_ERROR
;
615 Status
= PS2MouseSetResolution (MouseDev
->Resolution
);
616 if (EFI_ERROR (Status
)) {
617 Status
= EFI_DEVICE_ERROR
;
621 Status
= PS2MouseSetScaling (MouseDev
->Scaling
);
622 if (EFI_ERROR (Status
)) {
623 Status
= EFI_DEVICE_ERROR
;
627 Status
= PS2MouseEnable ();
628 if (EFI_ERROR (Status
)) {
629 Status
= EFI_DEVICE_ERROR
;
635 gBS
->RestoreTPL (OldTpl
);
637 if (KeyboardEnable
) {
645 Check whether there is Ps/2 mouse device in system
647 @param MouseDev - Mouse Private Data Structure
649 @retval TRUE - Keyboard in System.
650 @retval FALSE - Keyboard not in System.
655 IN PS2_MOUSE_DEV
*MouseDev
661 Status
= PS2MouseEnable ();
662 if (!EFI_ERROR (Status
)) {
670 Get and Clear mouse status.
672 @param This - Pointer of simple pointer Protocol.
673 @param State - Output buffer holding status.
675 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
676 @retval EFI_NOT_READY Mouse is not changed status yet.
677 @retval EFI_SUCCESS Mouse status is changed and get successful.
682 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
683 IN OUT EFI_SIMPLE_POINTER_STATE
*State
686 PS2_MOUSE_DEV
*MouseDev
;
689 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
692 return EFI_INVALID_PARAMETER
;
695 if (!MouseDev
->StateChanged
) {
696 return EFI_NOT_READY
;
699 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
700 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
705 MouseDev
->State
.RelativeMovementX
= 0;
706 MouseDev
->State
.RelativeMovementY
= 0;
707 MouseDev
->State
.RelativeMovementZ
= 0;
708 MouseDev
->StateChanged
= FALSE
;
709 gBS
->RestoreTPL (OldTpl
);
716 Event notification function for SIMPLE_POINTER.WaitForInput event.
717 Signal the event if there is input from mouse.
719 @param Event event object
720 @param Context event context
730 PS2_MOUSE_DEV
*MouseDev
;
732 MouseDev
= (PS2_MOUSE_DEV
*)Context
;
735 // Someone is waiting on the mouse event, if there's
736 // input from mouse, signal the event
738 if (MouseDev
->StateChanged
) {
739 gBS
->SignalEvent (Event
);
744 Event notification function for TimerEvent event.
745 If mouse device is connected to system, try to get the mouse packet data.
747 @param Event - TimerEvent in PS2_MOUSE_DEV
748 @param Context - Pointer to PS2_MOUSE_DEV structure
759 PS2_MOUSE_DEV
*MouseDev
;
761 MouseDev
= (PS2_MOUSE_DEV
*)Context
;
764 // Polling mouse packet data
766 PS2MouseGetPacket (MouseDev
);
770 The user Entry Point for module Ps2Mouse. The user code starts with this function.
772 @param[in] ImageHandle The firmware allocated handle for the EFI image.
773 @param[in] SystemTable A pointer to the EFI System Table.
775 @retval EFI_SUCCESS The entry point is executed successfully.
776 @retval other Some error occurs when executing this entry point.
782 IN EFI_HANDLE ImageHandle
,
783 IN EFI_SYSTEM_TABLE
*SystemTable
789 // Install driver model protocol(s).
791 Status
= EfiLibInstallDriverBindingComponentName2 (
796 &gPs2MouseComponentName
,
797 &gPs2MouseComponentName2
799 ASSERT_EFI_ERROR (Status
);