2 A faked PS/2 Absolute Pointer 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
10 #include "Ps2MouseAbsolutePointer.h"
14 // DriverBinding Protocol Instance
16 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseAbsolutePointerDriver
= {
17 PS2MouseAbsolutePointerDriverSupported
,
18 PS2MouseAbsolutePointerDriverStart
,
19 PS2MouseAbsolutePointerDriverStop
,
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 PS2MouseAbsolutePointerDriverSupported (
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 Mouse 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 PS2MouseAbsolutePointerDriverStart (
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_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
134 EFI_STATUS_CODE_VALUE StatusCode
;
135 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
138 MouseAbsolutePointerDev
= NULL
;
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 MouseAbsolutePointerDev
= AllocateZeroPool (sizeof (PS2_MOUSE_ABSOLUTE_POINTER_DEV
));
193 if (MouseAbsolutePointerDev
== NULL
) {
194 Status
= EFI_OUT_OF_RESOURCES
;
198 // Setup the device instance
200 MouseAbsolutePointerDev
->Signature
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE
;
201 MouseAbsolutePointerDev
->Handle
= Controller
;
202 MouseAbsolutePointerDev
->SampleRate
= SampleRate20
;
203 MouseAbsolutePointerDev
->Resolution
= MouseResolution4
;
204 MouseAbsolutePointerDev
->Scaling
= Scaling1
;
205 MouseAbsolutePointerDev
->DataPackageSize
= 3;
206 MouseAbsolutePointerDev
->IsaIo
= IsaIo
;
207 MouseAbsolutePointerDev
->DevicePath
= ParentDevicePath
;
210 // Resolution = 4 counts/mm
212 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxX
= 1024;
213 MouseAbsolutePointerDev
->Mode
.AbsoluteMinX
= 0;
214 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxY
= 798;
215 MouseAbsolutePointerDev
->Mode
.AbsoluteMinY
= 0;
216 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxZ
= 0;
217 MouseAbsolutePointerDev
->Mode
.AbsoluteMinZ
= 0;
218 MouseAbsolutePointerDev
->Mode
.Attributes
= 0x03;
220 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Reset
= MouseAbsolutePointerReset
;
221 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.GetState
= MouseAbsolutePointerGetState
;
222 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Mode
= &(MouseAbsolutePointerDev
->Mode
);
225 // Initialize keyboard controller if necessary
227 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
229 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
233 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
234 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
235 Status
= KbcSelfTest (IsaIo
);
236 if (EFI_ERROR (Status
)) {
237 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
242 KbcEnableAux (IsaIo
);
244 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
253 Status
= MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Reset (
254 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
,
255 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
257 if (EFI_ERROR (Status
)) {
259 // mouse not connected
261 Status
= EFI_SUCCESS
;
262 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
266 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
268 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
273 // Setup the WaitForKey event
275 Status
= gBS
->CreateEvent (
278 MouseAbsolutePointerWaitForInput
,
279 MouseAbsolutePointerDev
,
280 &((MouseAbsolutePointerDev
->AbsolutePointerProtocol
).WaitForInput
)
282 if (EFI_ERROR (Status
)) {
283 Status
= EFI_OUT_OF_RESOURCES
;
287 // Setup a periodic timer, used to poll mouse state
289 Status
= gBS
->CreateEvent (
290 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
292 PollMouseAbsolutePointer
,
293 MouseAbsolutePointerDev
,
294 &MouseAbsolutePointerDev
->TimerEvent
296 if (EFI_ERROR (Status
)) {
297 Status
= EFI_OUT_OF_RESOURCES
;
301 // Start timer to poll mouse (100 samples per second)
303 Status
= gBS
->SetTimer (MouseAbsolutePointerDev
->TimerEvent
, TimerPeriodic
, 100000);
304 if (EFI_ERROR (Status
)) {
305 Status
= EFI_OUT_OF_RESOURCES
;
309 MouseAbsolutePointerDev
->ControllerNameTable
= NULL
;
312 gPs2MouseAbsolutePointerComponentName
.SupportedLanguages
,
313 &MouseAbsolutePointerDev
->ControllerNameTable
,
314 L
"Faked PS/2 Touchpad Device",
319 gPs2MouseAbsolutePointerComponentName2
.SupportedLanguages
,
320 &MouseAbsolutePointerDev
->ControllerNameTable
,
321 L
"Faked PS/2 Touchpad Device",
327 // Install protocol interfaces for the mouse device.
329 Status
= gBS
->InstallMultipleProtocolInterfaces (
331 &gEfiAbsolutePointerProtocolGuid
,
332 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
,
335 if (EFI_ERROR (Status
)) {
339 gBS
->RestoreTPL (OldTpl
);
345 KbcDisableAux (IsaIo
);
347 if (StatusCode
!= 0) {
348 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
349 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
355 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
!= NULL
)) {
356 gBS
->CloseEvent (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
);
359 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->TimerEvent
!= NULL
)) {
360 gBS
->CloseEvent (MouseAbsolutePointerDev
->TimerEvent
);
363 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->ControllerNameTable
!= NULL
)) {
364 FreeUnicodeStringTable (MouseAbsolutePointerDev
->ControllerNameTable
);
367 // Since there will be no timer handler for mouse input any more,
368 // exhaust input data just in case there is still mouse data left
370 EmptyStatus
= EFI_SUCCESS
;
371 while (!EFI_ERROR (EmptyStatus
)) {
372 EmptyStatus
= In8042Data (IsaIo
, &Data
);
375 if (MouseAbsolutePointerDev
!= NULL
) {
376 FreePool (MouseAbsolutePointerDev
);
381 &gEfiDevicePathProtocolGuid
,
382 This
->DriverBindingHandle
,
388 &gEfiIsaIoProtocolGuid
,
389 This
->DriverBindingHandle
,
393 gBS
->RestoreTPL (OldTpl
);
399 Stop this driver on ControllerHandle. Support stopping any child handles
400 created by this driver.
402 @param This Protocol instance pointer.
403 @param ControllerHandle Handle of device to stop driver on
404 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
405 children is zero stop the entire bus driver.
406 @param ChildHandleBuffer List of Child Handles to Stop.
408 @retval EFI_SUCCESS This driver is removed ControllerHandle
409 @retval other This driver was not removed from this device
414 PS2MouseAbsolutePointerDriverStop (
415 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
416 IN EFI_HANDLE Controller
,
417 IN UINTN NumberOfChildren
,
418 IN EFI_HANDLE
*ChildHandleBuffer
422 EFI_ABSOLUTE_POINTER_PROTOCOL
*AbsolutePointerProtocol
;
423 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
426 Status
= gBS
->OpenProtocol (
428 &gEfiAbsolutePointerProtocolGuid
,
429 (VOID
**) &AbsolutePointerProtocol
,
430 This
->DriverBindingHandle
,
432 EFI_OPEN_PROTOCOL_GET_PROTOCOL
434 if (EFI_ERROR (Status
)) {
438 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (AbsolutePointerProtocol
);
441 // Report that the keyboard is being disabled
443 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
445 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
446 MouseAbsolutePointerDev
->DevicePath
449 Status
= gBS
->UninstallProtocolInterface (
451 &gEfiAbsolutePointerProtocolGuid
,
452 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
454 if (EFI_ERROR (Status
)) {
459 // Cancel mouse data polling timer, close timer event
461 gBS
->SetTimer (MouseAbsolutePointerDev
->TimerEvent
, TimerCancel
, 0);
462 gBS
->CloseEvent (MouseAbsolutePointerDev
->TimerEvent
);
465 // Since there will be no timer handler for mouse input any more,
466 // exhaust input data just in case there is still mouse data left
468 Status
= EFI_SUCCESS
;
469 while (!EFI_ERROR (Status
)) {
470 Status
= In8042Data (MouseAbsolutePointerDev
->IsaIo
, &Data
);
473 gBS
->CloseEvent (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
);
474 FreeUnicodeStringTable (MouseAbsolutePointerDev
->ControllerNameTable
);
475 FreePool (MouseAbsolutePointerDev
);
479 &gEfiDevicePathProtocolGuid
,
480 This
->DriverBindingHandle
,
486 &gEfiIsaIoProtocolGuid
,
487 This
->DriverBindingHandle
,
495 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and there is a mouse device connected to system.
497 @param This - Pointer of simple pointer Protocol.
498 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
501 @retval EFI_SUCCESS - The command byte is written successfully.
502 @retval EFI_DEVICE_ERROR - Errors occurred during resetting keyboard.
507 MouseAbsolutePointerReset (
508 IN EFI_ABSOLUTE_POINTER_PROTOCOL
*This
,
509 IN BOOLEAN ExtendedVerification
513 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
515 BOOLEAN KeyboardEnable
;
518 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This
);
521 // Report reset progress code
523 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
525 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
526 MouseAbsolutePointerDev
->DevicePath
529 KeyboardEnable
= FALSE
;
532 // Raise TPL to avoid keyboard operation impact
534 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
536 ZeroMem (&MouseAbsolutePointerDev
->State
, sizeof (EFI_ABSOLUTE_POINTER_STATE
));
537 MouseAbsolutePointerDev
->StateChanged
= FALSE
;
540 // Exhaust input data
542 Status
= EFI_SUCCESS
;
543 while (!EFI_ERROR (Status
)) {
544 Status
= In8042Data (MouseAbsolutePointerDev
->IsaIo
, &Data
);
547 CheckKbStatus (MouseAbsolutePointerDev
->IsaIo
, &KeyboardEnable
);
549 KbcDisableKb (MouseAbsolutePointerDev
->IsaIo
);
551 MouseAbsolutePointerDev
->IsaIo
->Io
.Read (MouseAbsolutePointerDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
554 // if there's data block on KBC data port, read it out
556 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
557 MouseAbsolutePointerDev
->IsaIo
->Io
.Read (MouseAbsolutePointerDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
560 Status
= EFI_SUCCESS
;
562 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
563 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
564 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
566 if (ExtendedVerification
&& CheckMouseAbsolutePointerConnect (MouseAbsolutePointerDev
)) {
568 // Send mouse reset command and set mouse default configure
570 Status
= PS2MouseReset (MouseAbsolutePointerDev
->IsaIo
);
571 if (EFI_ERROR (Status
)) {
572 Status
= EFI_DEVICE_ERROR
;
576 Status
= PS2MouseSetSampleRate (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->SampleRate
);
577 if (EFI_ERROR (Status
)) {
578 Status
= EFI_DEVICE_ERROR
;
582 Status
= PS2MouseSetResolution (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->Resolution
);
583 if (EFI_ERROR (Status
)) {
584 Status
= EFI_DEVICE_ERROR
;
588 Status
= PS2MouseSetScaling (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->Scaling
);
589 if (EFI_ERROR (Status
)) {
590 Status
= EFI_DEVICE_ERROR
;
594 Status
= PS2MouseEnable (MouseAbsolutePointerDev
->IsaIo
);
595 if (EFI_ERROR (Status
)) {
596 Status
= EFI_DEVICE_ERROR
;
601 gBS
->RestoreTPL (OldTpl
);
603 if (KeyboardEnable
) {
604 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
611 Check whether there is Ps/2 mouse device in system
613 @param MouseAbsolutePointerDev - Absolute Pointer Device Private Data Structure
615 @retval TRUE - Keyboard in System.
616 @retval FALSE - Keyboard not in System.
620 CheckMouseAbsolutePointerConnect (
621 IN PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
627 Status
= PS2MouseEnable (MouseAbsolutePointerDev
->IsaIo
);
628 if (!EFI_ERROR (Status
)) {
636 Get and Clear mouse status.
638 @param This - Pointer of simple pointer Protocol.
639 @param State - Output buffer holding status.
641 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
642 @retval EFI_NOT_READY Mouse is not changed status yet.
643 @retval EFI_SUCCESS Mouse status is changed and get successful.
647 MouseAbsolutePointerGetState (
648 IN EFI_ABSOLUTE_POINTER_PROTOCOL
*This
,
649 IN OUT EFI_ABSOLUTE_POINTER_STATE
*State
652 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
655 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This
);
658 return EFI_INVALID_PARAMETER
;
661 if (!MouseAbsolutePointerDev
->StateChanged
) {
662 return EFI_NOT_READY
;
665 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
666 CopyMem (State
, &(MouseAbsolutePointerDev
->State
), sizeof (EFI_ABSOLUTE_POINTER_STATE
));
671 MouseAbsolutePointerDev
->State
.CurrentX
= 0;
672 MouseAbsolutePointerDev
->State
.CurrentY
= 0;
673 MouseAbsolutePointerDev
->State
.CurrentZ
= 0;
674 MouseAbsolutePointerDev
->State
.ActiveButtons
= 0x0;
675 MouseAbsolutePointerDev
->StateChanged
= FALSE
;
676 gBS
->RestoreTPL (OldTpl
);
683 Event notification function for SIMPLE_POINTER.WaitForInput event.
684 Signal the event if there is input from mouse.
686 @param Event event object
687 @param Context event context
692 MouseAbsolutePointerWaitForInput (
697 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
699 MouseAbsolutePointerDev
= (PS2_MOUSE_ABSOLUTE_POINTER_DEV
*) Context
;
702 // Someone is waiting on the mouse event, if there's
703 // input from mouse, signal the event
705 if (MouseAbsolutePointerDev
->StateChanged
) {
706 gBS
->SignalEvent (Event
);
712 Event notification function for TimerEvent event.
713 If mouse device is connected to system, try to get the mouse packet data.
715 @param Event - TimerEvent in PS2_MOUSE_DEV
716 @param Context - Pointer to PS2_MOUSE_DEV structure
721 PollMouseAbsolutePointer(
727 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
729 MouseAbsolutePointerDev
= (PS2_MOUSE_ABSOLUTE_POINTER_DEV
*) Context
;
732 // Polling mouse packet data
734 PS2MouseGetPacket (MouseAbsolutePointerDev
);
738 The user Entry Point for module Ps2MouseAbsolutePointer. The user code starts with this function.
740 @param[in] ImageHandle The firmware allocated handle for the EFI image.
741 @param[in] SystemTable A pointer to the EFI System Table.
743 @retval EFI_SUCCESS The entry point is executed successfully.
744 @retval other Some error occurs when executing this entry point.
749 InitializePs2MouseAbsolutePointer(
750 IN EFI_HANDLE ImageHandle
,
751 IN EFI_SYSTEM_TABLE
*SystemTable
757 // Install driver model protocol(s).
759 Status
= EfiLibInstallDriverBindingComponentName2 (
762 &gPS2MouseAbsolutePointerDriver
,
764 &gPs2MouseAbsolutePointerComponentName
,
765 &gPs2MouseAbsolutePointerComponentName2
767 ASSERT_EFI_ERROR (Status
);