2 PS/2 Mouse driver. Routines that interacts with callers,
3 conforming to EFI driver model.
5 Copyright (c) 2006 - 2018, 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_ISA_IO_PROTOCOL
*IsaIo
;
53 // Open the IO Abstraction(s) needed to perform the supported test
55 Status
= gBS
->OpenProtocol (
57 &gEfiIsaIoProtocolGuid
,
59 This
->DriverBindingHandle
,
61 EFI_OPEN_PROTOCOL_BY_DRIVER
63 if (EFI_ERROR (Status
)) {
67 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
69 switch (IsaIo
->ResourceList
->Device
.HID
) {
70 case EISA_PNP_ID (0xF03):
72 // Microsoft PS/2 style mouse
74 case EISA_PNP_ID (0xF13):
76 // PS/2 Port for PS/2-style Mice
80 case EISA_PNP_ID (0x303):
82 // IBM Enhanced (101/102-key, PS/2 mouse support)
84 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
89 Status
= EFI_UNSUPPORTED
;
93 // Close the I/O Abstraction(s) used to perform the supported test
97 &gEfiIsaIoProtocolGuid
,
98 This
->DriverBindingHandle
,
106 Start this driver on ControllerHandle by opening a IsaIo protocol, creating
107 PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
110 @param This Protocol instance pointer.
111 @param ControllerHandle Handle of device to bind driver to
112 @param RemainingDevicePath Optional parameter use to pick a specific child
115 @retval EFI_SUCCESS This driver is added to ControllerHandle
116 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
117 @retval other This driver does not support this device
122 PS2MouseDriverStart (
123 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
124 IN EFI_HANDLE Controller
,
125 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
129 EFI_STATUS EmptyStatus
;
130 EFI_ISA_IO_PROTOCOL
*IsaIo
;
131 PS2_MOUSE_DEV
*MouseDev
;
134 EFI_STATUS_CODE_VALUE StatusCode
;
135 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
142 // Open the device path protocol
144 Status
= gBS
->OpenProtocol (
146 &gEfiDevicePathProtocolGuid
,
147 (VOID
**) &ParentDevicePath
,
148 This
->DriverBindingHandle
,
150 EFI_OPEN_PROTOCOL_BY_DRIVER
152 if (EFI_ERROR (Status
)) {
156 // Report that the keyboard is being enabled
158 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
160 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
165 // Get the ISA I/O Protocol on Controller's handle
167 Status
= gBS
->OpenProtocol (
169 &gEfiIsaIoProtocolGuid
,
171 This
->DriverBindingHandle
,
173 EFI_OPEN_PROTOCOL_BY_DRIVER
175 if (EFI_ERROR (Status
)) {
178 &gEfiDevicePathProtocolGuid
,
179 This
->DriverBindingHandle
,
182 return EFI_INVALID_PARAMETER
;
185 // Raise TPL to avoid keyboard operation impact
187 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
190 // Allocate private data
192 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
193 if (MouseDev
== NULL
) {
194 Status
= EFI_OUT_OF_RESOURCES
;
198 // Setup the device instance
200 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
201 MouseDev
->Handle
= Controller
;
202 MouseDev
->SampleRate
= SampleRate20
;
203 MouseDev
->Resolution
= MouseResolution4
;
204 MouseDev
->Scaling
= Scaling1
;
205 MouseDev
->DataPackageSize
= 3;
206 MouseDev
->IsaIo
= IsaIo
;
207 MouseDev
->DevicePath
= ParentDevicePath
;
210 // Resolution = 4 counts/mm
212 MouseDev
->Mode
.ResolutionX
= 4;
213 MouseDev
->Mode
.ResolutionY
= 4;
214 MouseDev
->Mode
.LeftButton
= TRUE
;
215 MouseDev
->Mode
.RightButton
= TRUE
;
217 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
218 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
219 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
222 // Initialize keyboard controller if necessary
224 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
226 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
228 if ((Data
& (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
230 // If nobody decodes KBC I/O port, it will read back as 0xFF.
231 // Check the Time-Out and Parity bit to see if it has an active KBC in system
233 Status
= EFI_DEVICE_ERROR
;
234 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
238 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
240 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
244 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
245 Status
= KbcSelfTest (IsaIo
);
246 if (EFI_ERROR (Status
)) {
247 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
252 KbcEnableAux (IsaIo
);
254 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
256 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
263 Status
= MouseDev
->SimplePointerProtocol
.Reset (
264 &MouseDev
->SimplePointerProtocol
,
265 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
267 if (EFI_ERROR (Status
)) {
269 // mouse not connected
271 Status
= EFI_SUCCESS
;
272 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
276 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
278 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
283 // Setup the WaitForKey event
285 Status
= gBS
->CreateEvent (
290 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
292 if (EFI_ERROR (Status
)) {
293 Status
= EFI_OUT_OF_RESOURCES
;
297 // Setup a periodic timer, used to poll mouse state
299 Status
= gBS
->CreateEvent (
300 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
304 &MouseDev
->TimerEvent
306 if (EFI_ERROR (Status
)) {
307 Status
= EFI_OUT_OF_RESOURCES
;
311 // Start timer to poll mouse (100 samples per second)
313 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
314 if (EFI_ERROR (Status
)) {
315 Status
= EFI_OUT_OF_RESOURCES
;
319 MouseDev
->ControllerNameTable
= NULL
;
322 gPs2MouseComponentName
.SupportedLanguages
,
323 &MouseDev
->ControllerNameTable
,
324 L
"PS/2 Mouse Device",
329 gPs2MouseComponentName2
.SupportedLanguages
,
330 &MouseDev
->ControllerNameTable
,
331 L
"PS/2 Mouse Device",
337 // Install protocol interfaces for the mouse device.
339 Status
= gBS
->InstallMultipleProtocolInterfaces (
341 &gEfiSimplePointerProtocolGuid
,
342 &MouseDev
->SimplePointerProtocol
,
345 if (EFI_ERROR (Status
)) {
349 gBS
->RestoreTPL (OldTpl
);
355 if (Status
!= EFI_DEVICE_ERROR
) {
356 KbcDisableAux (IsaIo
);
359 if (StatusCode
!= 0) {
360 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
361 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
367 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
368 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
371 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
372 gBS
->CloseEvent (MouseDev
->TimerEvent
);
375 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
376 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
379 if (Status
!= EFI_DEVICE_ERROR
) {
381 // Since there will be no timer handler for mouse input any more,
382 // exhaust input data just in case there is still mouse data left
384 EmptyStatus
= EFI_SUCCESS
;
385 while (!EFI_ERROR (EmptyStatus
)) {
386 EmptyStatus
= In8042Data (IsaIo
, &Data
);
390 if (MouseDev
!= NULL
) {
396 &gEfiDevicePathProtocolGuid
,
397 This
->DriverBindingHandle
,
403 &gEfiIsaIoProtocolGuid
,
404 This
->DriverBindingHandle
,
408 gBS
->RestoreTPL (OldTpl
);
414 Stop this driver on ControllerHandle. Support stopping any child handles
415 created by this driver.
417 @param This Protocol instance pointer.
418 @param ControllerHandle Handle of device to stop driver on
419 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
420 children is zero stop the entire bus driver.
421 @param ChildHandleBuffer List of Child Handles to Stop.
423 @retval EFI_SUCCESS This driver is removed ControllerHandle
424 @retval other This driver was not removed from this device
430 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
431 IN EFI_HANDLE Controller
,
432 IN UINTN NumberOfChildren
,
433 IN EFI_HANDLE
*ChildHandleBuffer
437 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
438 PS2_MOUSE_DEV
*MouseDev
;
441 Status
= gBS
->OpenProtocol (
443 &gEfiSimplePointerProtocolGuid
,
444 (VOID
**) &SimplePointerProtocol
,
445 This
->DriverBindingHandle
,
447 EFI_OPEN_PROTOCOL_GET_PROTOCOL
449 if (EFI_ERROR (Status
)) {
453 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
456 // Report that the keyboard is being disabled
458 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
460 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
464 Status
= gBS
->UninstallProtocolInterface (
466 &gEfiSimplePointerProtocolGuid
,
467 &MouseDev
->SimplePointerProtocol
469 if (EFI_ERROR (Status
)) {
474 // Cancel mouse data polling timer, close timer event
476 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
477 gBS
->CloseEvent (MouseDev
->TimerEvent
);
480 // Since there will be no timer handler for mouse input any more,
481 // exhaust input data just in case there is still mouse data left
483 Status
= EFI_SUCCESS
;
484 while (!EFI_ERROR (Status
)) {
485 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
488 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
489 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
494 &gEfiDevicePathProtocolGuid
,
495 This
->DriverBindingHandle
,
501 &gEfiIsaIoProtocolGuid
,
502 This
->DriverBindingHandle
,
510 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and there is a mouse device connected to system
512 @param This - Pointer of simple pointer Protocol.
513 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
516 @retval EFI_SUCCESS - The command byte is written successfully.
517 @retval EFI_DEVICE_ERROR - Errors occurred during resetting keyboard.
523 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
524 IN BOOLEAN ExtendedVerification
528 PS2_MOUSE_DEV
*MouseDev
;
530 BOOLEAN KeyboardEnable
;
533 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
536 // Report reset progress code
538 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
540 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
544 KeyboardEnable
= FALSE
;
547 // Raise TPL to avoid keyboard operation impact
549 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
551 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
552 MouseDev
->StateChanged
= FALSE
;
555 // Exhaust input data
557 Status
= EFI_SUCCESS
;
558 while (!EFI_ERROR (Status
)) {
559 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
562 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
564 KbcDisableKb (MouseDev
->IsaIo
);
566 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
569 // if there's data block on KBC data port, read it out
571 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
572 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
575 Status
= EFI_SUCCESS
;
577 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
578 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
579 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
581 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
583 // Send mouse reset command and set mouse default configure
585 Status
= PS2MouseReset (MouseDev
->IsaIo
);
586 if (EFI_ERROR (Status
)) {
587 Status
= EFI_DEVICE_ERROR
;
591 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
592 if (EFI_ERROR (Status
)) {
593 Status
= EFI_DEVICE_ERROR
;
597 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
598 if (EFI_ERROR (Status
)) {
599 Status
= EFI_DEVICE_ERROR
;
603 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
604 if (EFI_ERROR (Status
)) {
605 Status
= EFI_DEVICE_ERROR
;
609 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
610 if (EFI_ERROR (Status
)) {
611 Status
= EFI_DEVICE_ERROR
;
616 gBS
->RestoreTPL (OldTpl
);
618 if (KeyboardEnable
) {
619 KbcEnableKb (MouseDev
->IsaIo
);
626 Check whether there is Ps/2 mouse device in system
628 @param MouseDev - Mouse Private Data Structure
630 @retval TRUE - Keyboard in System.
631 @retval FALSE - Keyboard not in System.
636 IN PS2_MOUSE_DEV
*MouseDev
642 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
643 if (!EFI_ERROR (Status
)) {
651 Get and Clear mouse status.
653 @param This - Pointer of simple pointer Protocol.
654 @param State - Output buffer holding status.
656 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
657 @retval EFI_NOT_READY Mouse is not changed status yet.
658 @retval EFI_SUCCESS Mouse status is changed and get successful.
663 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
664 IN OUT EFI_SIMPLE_POINTER_STATE
*State
667 PS2_MOUSE_DEV
*MouseDev
;
670 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
673 return EFI_INVALID_PARAMETER
;
676 if (!MouseDev
->StateChanged
) {
677 return EFI_NOT_READY
;
680 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
681 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
686 MouseDev
->State
.RelativeMovementX
= 0;
687 MouseDev
->State
.RelativeMovementY
= 0;
688 MouseDev
->State
.RelativeMovementZ
= 0;
689 MouseDev
->StateChanged
= FALSE
;
690 gBS
->RestoreTPL (OldTpl
);
697 Event notification function for SIMPLE_POINTER.WaitForInput event.
698 Signal the event if there is input from mouse.
700 @param Event event object
701 @param Context event context
711 PS2_MOUSE_DEV
*MouseDev
;
713 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
716 // Someone is waiting on the mouse event, if there's
717 // input from mouse, signal the event
719 if (MouseDev
->StateChanged
) {
720 gBS
->SignalEvent (Event
);
726 Event notification function for TimerEvent event.
727 If mouse device is connected to system, try to get the mouse packet data.
729 @param Event - TimerEvent in PS2_MOUSE_DEV
730 @param Context - Pointer to PS2_MOUSE_DEV structure
741 PS2_MOUSE_DEV
*MouseDev
;
743 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
746 // Polling mouse packet data
748 PS2MouseGetPacket (MouseDev
);
752 The user Entry Point for module Ps2Mouse. The user code starts with this function.
754 @param[in] ImageHandle The firmware allocated handle for the EFI image.
755 @param[in] SystemTable A pointer to the EFI System Table.
757 @retval EFI_SUCCESS The entry point is executed successfully.
758 @retval other Some error occurs when executing this entry point.
764 IN EFI_HANDLE ImageHandle
,
765 IN EFI_SYSTEM_TABLE
*SystemTable
771 // Install driver model protocol(s).
773 Status
= EfiLibInstallDriverBindingComponentName2 (
778 &gPs2MouseComponentName
,
779 &gPs2MouseComponentName2
781 ASSERT_EFI_ERROR (Status
);