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
,
58 (VOID
**) &DevicePath
,
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
)) {
74 return EFI_UNSUPPORTED
;
78 case EISA_PNP_ID (0xF03):
80 // Microsoft PS/2 style mouse
82 case EISA_PNP_ID (0xF13):
84 // PS/2 Port for PS/2-style Mice
88 case EISA_PNP_ID (0x303):
90 // IBM Enhanced (101/102-key, PS/2 mouse support)
97 return EFI_UNSUPPORTED
;
102 // Open the IO Abstraction(s) needed to perform the supported test
104 Status
= gBS
->OpenProtocol (
106 &gEfiSioProtocolGuid
,
108 This
->DriverBindingHandle
,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
112 if (EFI_ERROR (Status
)) {
117 // Close the I/O Abstraction(s) used to perform the supported test
121 &gEfiSioProtocolGuid
,
122 This
->DriverBindingHandle
,
130 Start this driver on ControllerHandle by opening a Sio protocol, creating
131 PS2_MOUSE_DEV device and install gEfiSimplePointerProtocolGuid finally.
133 @param This Protocol instance pointer.
134 @param ControllerHandle Handle of device to bind driver to
135 @param RemainingDevicePath Optional parameter use to pick a specific child
138 @retval EFI_SUCCESS This driver is added to ControllerHandle
139 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
140 @retval other This driver does not support this device
145 PS2MouseDriverStart (
146 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
147 IN EFI_HANDLE Controller
,
148 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
152 EFI_STATUS EmptyStatus
;
153 EFI_SIO_PROTOCOL
*Sio
;
154 PS2_MOUSE_DEV
*MouseDev
;
157 EFI_STATUS_CODE_VALUE StatusCode
;
158 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
163 // Open the device path protocol
165 Status
= gBS
->OpenProtocol (
167 &gEfiDevicePathProtocolGuid
,
168 (VOID
**) &DevicePath
,
169 This
->DriverBindingHandle
,
171 EFI_OPEN_PROTOCOL_GET_PROTOCOL
173 if (EFI_ERROR (Status
)) {
177 // Report that the keyboard is being enabled
179 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
181 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
186 // Get the ISA I/O Protocol on Controller's handle
188 Status
= gBS
->OpenProtocol (
190 &gEfiSioProtocolGuid
,
192 This
->DriverBindingHandle
,
194 EFI_OPEN_PROTOCOL_BY_DRIVER
196 if (EFI_ERROR (Status
)) {
200 // Raise TPL to avoid keyboard operation impact
202 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
205 // Allocate private data
207 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
208 if (MouseDev
== NULL
) {
209 Status
= EFI_OUT_OF_RESOURCES
;
213 // Setup the device instance
215 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
216 MouseDev
->Handle
= Controller
;
217 MouseDev
->SampleRate
= SampleRate20
;
218 MouseDev
->Resolution
= MouseResolution4
;
219 MouseDev
->Scaling
= Scaling1
;
220 MouseDev
->DataPackageSize
= 3;
221 MouseDev
->DevicePath
= DevicePath
;
224 // Resolution = 4 counts/mm
226 MouseDev
->Mode
.ResolutionX
= 4;
227 MouseDev
->Mode
.ResolutionY
= 4;
228 MouseDev
->Mode
.LeftButton
= TRUE
;
229 MouseDev
->Mode
.RightButton
= TRUE
;
231 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
232 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
233 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
236 // Initialize keyboard controller if necessary
238 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
240 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
244 Data
= IoRead8 (KBC_CMD_STS_PORT
);
246 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
248 if ((Data
& (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
250 // If nobody decodes KBC I/O port, it will read back as 0xFF.
251 // Check the Time-Out and Parity bit to see if it has an active KBC in system
253 Status
= EFI_DEVICE_ERROR
;
254 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
258 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
259 Status
= KbcSelfTest ();
260 if (EFI_ERROR (Status
)) {
261 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
268 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
270 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
277 Status
= MouseDev
->SimplePointerProtocol
.Reset (
278 &MouseDev
->SimplePointerProtocol
,
279 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
281 if (EFI_ERROR (Status
)) {
283 // mouse not connected
285 Status
= EFI_SUCCESS
;
286 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
290 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
292 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
297 // Setup the WaitForKey event
299 Status
= gBS
->CreateEvent (
304 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
306 if (EFI_ERROR (Status
)) {
307 Status
= EFI_OUT_OF_RESOURCES
;
311 // Setup a periodic timer, used to poll mouse state
313 Status
= gBS
->CreateEvent (
314 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
318 &MouseDev
->TimerEvent
320 if (EFI_ERROR (Status
)) {
321 Status
= EFI_OUT_OF_RESOURCES
;
325 // Start timer to poll mouse (100 samples per second)
327 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
328 if (EFI_ERROR (Status
)) {
329 Status
= EFI_OUT_OF_RESOURCES
;
333 MouseDev
->ControllerNameTable
= NULL
;
336 gPs2MouseComponentName
.SupportedLanguages
,
337 &MouseDev
->ControllerNameTable
,
338 L
"PS/2 Mouse Device",
343 gPs2MouseComponentName2
.SupportedLanguages
,
344 &MouseDev
->ControllerNameTable
,
345 L
"PS/2 Mouse Device",
351 // Install protocol interfaces for the mouse device.
353 Status
= gBS
->InstallMultipleProtocolInterfaces (
355 &gEfiSimplePointerProtocolGuid
,
356 &MouseDev
->SimplePointerProtocol
,
359 if (EFI_ERROR (Status
)) {
363 gBS
->RestoreTPL (OldTpl
);
369 if (Status
!= EFI_DEVICE_ERROR
) {
373 if (StatusCode
!= 0) {
374 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
375 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
381 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
382 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
385 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
386 gBS
->CloseEvent (MouseDev
->TimerEvent
);
389 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
390 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
393 if (Status
!= EFI_DEVICE_ERROR
) {
395 // Since there will be no timer handler for mouse input any more,
396 // exhaust input data just in case there is still mouse data left
398 EmptyStatus
= EFI_SUCCESS
;
399 while (!EFI_ERROR (EmptyStatus
)) {
400 EmptyStatus
= In8042Data (&Data
);
404 if (MouseDev
!= NULL
) {
410 &gEfiDevicePathProtocolGuid
,
411 This
->DriverBindingHandle
,
417 &gEfiSioProtocolGuid
,
418 This
->DriverBindingHandle
,
422 gBS
->RestoreTPL (OldTpl
);
428 Stop this driver on ControllerHandle. Support stopping any child handles
429 created by this driver.
431 @param This Protocol instance pointer.
432 @param ControllerHandle Handle of device to stop driver on
433 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
434 children is zero stop the entire bus driver.
435 @param ChildHandleBuffer List of Child Handles to Stop.
437 @retval EFI_SUCCESS This driver is removed ControllerHandle
438 @retval other This driver was not removed from this device
444 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
445 IN EFI_HANDLE Controller
,
446 IN UINTN NumberOfChildren
,
447 IN EFI_HANDLE
*ChildHandleBuffer
451 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
452 PS2_MOUSE_DEV
*MouseDev
;
455 Status
= gBS
->OpenProtocol (
457 &gEfiSimplePointerProtocolGuid
,
458 (VOID
**) &SimplePointerProtocol
,
459 This
->DriverBindingHandle
,
461 EFI_OPEN_PROTOCOL_GET_PROTOCOL
463 if (EFI_ERROR (Status
)) {
467 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
470 // Report that the keyboard is being disabled
472 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
474 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
478 Status
= gBS
->UninstallProtocolInterface (
480 &gEfiSimplePointerProtocolGuid
,
481 &MouseDev
->SimplePointerProtocol
483 if (EFI_ERROR (Status
)) {
488 // Cancel mouse data polling timer, close timer event
490 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
491 gBS
->CloseEvent (MouseDev
->TimerEvent
);
494 // Since there will be no timer handler for mouse input any more,
495 // exhaust input data just in case there is still mouse data left
497 Status
= EFI_SUCCESS
;
498 while (!EFI_ERROR (Status
)) {
499 Status
= In8042Data (&Data
);
502 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
503 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
508 &gEfiDevicePathProtocolGuid
,
509 This
->DriverBindingHandle
,
515 &gEfiSioProtocolGuid
,
516 This
->DriverBindingHandle
,
524 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and
525 there is a mouse device connected to system.
527 @param This - Pointer of simple pointer Protocol.
528 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
531 @retval EFI_SUCCESS - The command byte is written successfully.
532 @retval EFI_DEVICE_ERROR - Errors occurred during resetting keyboard.
538 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
539 IN BOOLEAN ExtendedVerification
543 PS2_MOUSE_DEV
*MouseDev
;
545 BOOLEAN KeyboardEnable
;
548 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
551 // Report reset progress code
553 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
555 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
559 KeyboardEnable
= FALSE
;
562 // Raise TPL to avoid keyboard operation impact
564 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
566 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
567 MouseDev
->StateChanged
= FALSE
;
570 // Exhaust input data
572 Status
= EFI_SUCCESS
;
573 while (!EFI_ERROR (Status
)) {
574 Status
= In8042Data (&Data
);
577 CheckKbStatus (&KeyboardEnable
);
582 // if there's data block on KBC data port, read it out
584 if ((IoRead8 (KBC_CMD_STS_PORT
) & KBC_OUTB
) == KBC_OUTB
) {
585 IoRead8 (KBC_DATA_PORT
);
588 Status
= EFI_SUCCESS
;
590 // The PS2 mouse driver reset behavior is always successfully return no matter whether or not there is mouse connected to system.
591 // This behavior is needed by performance speed. The following mouse command only successfully finish when mouse device is
592 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
594 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
596 // Send mouse reset command and set mouse default configure
598 Status
= PS2MouseReset ();
599 if (EFI_ERROR (Status
)) {
600 Status
= EFI_DEVICE_ERROR
;
604 Status
= PS2MouseSetSampleRate (MouseDev
->SampleRate
);
605 if (EFI_ERROR (Status
)) {
606 Status
= EFI_DEVICE_ERROR
;
610 Status
= PS2MouseSetResolution (MouseDev
->Resolution
);
611 if (EFI_ERROR (Status
)) {
612 Status
= EFI_DEVICE_ERROR
;
616 Status
= PS2MouseSetScaling (MouseDev
->Scaling
);
617 if (EFI_ERROR (Status
)) {
618 Status
= EFI_DEVICE_ERROR
;
622 Status
= PS2MouseEnable ();
623 if (EFI_ERROR (Status
)) {
624 Status
= EFI_DEVICE_ERROR
;
629 gBS
->RestoreTPL (OldTpl
);
631 if (KeyboardEnable
) {
639 Check whether there is Ps/2 mouse device in system
641 @param MouseDev - Mouse Private Data Structure
643 @retval TRUE - Keyboard in System.
644 @retval FALSE - Keyboard not in System.
649 IN PS2_MOUSE_DEV
*MouseDev
655 Status
= PS2MouseEnable ();
656 if (!EFI_ERROR (Status
)) {
664 Get and Clear mouse status.
666 @param This - Pointer of simple pointer Protocol.
667 @param State - Output buffer holding status.
669 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
670 @retval EFI_NOT_READY Mouse is not changed status yet.
671 @retval EFI_SUCCESS Mouse status is changed and get successful.
676 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
677 IN OUT EFI_SIMPLE_POINTER_STATE
*State
680 PS2_MOUSE_DEV
*MouseDev
;
683 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
686 return EFI_INVALID_PARAMETER
;
689 if (!MouseDev
->StateChanged
) {
690 return EFI_NOT_READY
;
693 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
694 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
699 MouseDev
->State
.RelativeMovementX
= 0;
700 MouseDev
->State
.RelativeMovementY
= 0;
701 MouseDev
->State
.RelativeMovementZ
= 0;
702 MouseDev
->StateChanged
= FALSE
;
703 gBS
->RestoreTPL (OldTpl
);
710 Event notification function for SIMPLE_POINTER.WaitForInput event.
711 Signal the event if there is input from mouse.
713 @param Event event object
714 @param Context event context
724 PS2_MOUSE_DEV
*MouseDev
;
726 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
729 // Someone is waiting on the mouse event, if there's
730 // input from mouse, signal the event
732 if (MouseDev
->StateChanged
) {
733 gBS
->SignalEvent (Event
);
739 Event notification function for TimerEvent event.
740 If mouse device is connected to system, try to get the mouse packet data.
742 @param Event - TimerEvent in PS2_MOUSE_DEV
743 @param Context - Pointer to PS2_MOUSE_DEV structure
754 PS2_MOUSE_DEV
*MouseDev
;
756 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
759 // Polling mouse packet data
761 PS2MouseGetPacket (MouseDev
);
765 The user Entry Point for module Ps2Mouse. The user code starts with this function.
767 @param[in] ImageHandle The firmware allocated handle for the EFI image.
768 @param[in] SystemTable A pointer to the EFI System Table.
770 @retval EFI_SUCCESS The entry point is executed successfully.
771 @retval other Some error occurs when executing this entry point.
777 IN EFI_HANDLE ImageHandle
,
778 IN EFI_SYSTEM_TABLE
*SystemTable
784 // Install driver model protocol(s).
786 Status
= EfiLibInstallDriverBindingComponentName2 (
791 &gPs2MouseComponentName
,
792 &gPs2MouseComponentName2
794 ASSERT_EFI_ERROR (Status
);