2 A faked PS/2 Absolute Pointer driver. Routines that interacts with callers,
3 conforming to EFI driver model
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Ps2MouseAbsolutePointer.h"
20 // DriverBinding Protocol Instance
22 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseAbsolutePointerDriver
= {
23 PS2MouseAbsolutePointerDriverSupported
,
24 PS2MouseAbsolutePointerDriverStart
,
25 PS2MouseAbsolutePointerDriverStop
,
32 Test to see if this driver supports ControllerHandle. Any ControllerHandle
33 than contains a IsaIo protocol can be supported.
35 @param This Protocol instance pointer.
36 @param ControllerHandle Handle of device to test
37 @param RemainingDevicePath Optional parameter use to pick a specific child
40 @retval EFI_SUCCESS This driver supports this device
41 @retval EFI_ALREADY_STARTED This driver is already running on this device
42 @retval other This driver does not support this device
47 PS2MouseAbsolutePointerDriverSupported (
48 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
49 IN EFI_HANDLE Controller
,
50 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
54 EFI_ISA_IO_PROTOCOL
*IsaIo
;
59 // Open the IO Abstraction(s) needed to perform the supported test
61 Status
= gBS
->OpenProtocol (
63 &gEfiIsaIoProtocolGuid
,
65 This
->DriverBindingHandle
,
67 EFI_OPEN_PROTOCOL_BY_DRIVER
69 if (EFI_ERROR (Status
)) {
73 // Use the ISA I/O Protocol to see if Controller is the Mouse controller
75 switch (IsaIo
->ResourceList
->Device
.HID
) {
76 case EISA_PNP_ID (0xF03):
78 // Microsoft PS/2 style mouse
80 case EISA_PNP_ID (0xF13):
82 // PS/2 Port for PS/2-style Mice
86 case EISA_PNP_ID (0x303):
88 // IBM Enhanced (101/102-key, PS/2 mouse support)
90 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
95 Status
= EFI_UNSUPPORTED
;
99 // Close the I/O Abstraction(s) used to perform the supported test
103 &gEfiIsaIoProtocolGuid
,
104 This
->DriverBindingHandle
,
112 Start this driver on ControllerHandle by opening a IsaIo protocol, creating
113 PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
116 @param This Protocol instance pointer.
117 @param ControllerHandle Handle of device to bind driver to
118 @param RemainingDevicePath Optional parameter use to pick a specific child
121 @retval EFI_SUCCESS This driver is added to ControllerHandle
122 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
123 @retval other This driver does not support this device
128 PS2MouseAbsolutePointerDriverStart (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE Controller
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
135 EFI_STATUS EmptyStatus
;
136 EFI_ISA_IO_PROTOCOL
*IsaIo
;
137 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
140 EFI_STATUS_CODE_VALUE StatusCode
;
141 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
144 MouseAbsolutePointerDev
= NULL
;
148 // Open the device path protocol
150 Status
= gBS
->OpenProtocol (
152 &gEfiDevicePathProtocolGuid
,
153 (VOID
**) &ParentDevicePath
,
154 This
->DriverBindingHandle
,
156 EFI_OPEN_PROTOCOL_BY_DRIVER
158 if (EFI_ERROR (Status
)) {
162 // Report that the keyboard is being enabled
164 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
166 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
171 // Get the ISA I/O Protocol on Controller's handle
173 Status
= gBS
->OpenProtocol (
175 &gEfiIsaIoProtocolGuid
,
177 This
->DriverBindingHandle
,
179 EFI_OPEN_PROTOCOL_BY_DRIVER
181 if (EFI_ERROR (Status
)) {
184 &gEfiDevicePathProtocolGuid
,
185 This
->DriverBindingHandle
,
188 return EFI_INVALID_PARAMETER
;
191 // Raise TPL to avoid keyboard operation impact
193 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
196 // Allocate private data
198 MouseAbsolutePointerDev
= AllocateZeroPool (sizeof (PS2_MOUSE_ABSOLUTE_POINTER_DEV
));
199 if (MouseAbsolutePointerDev
== NULL
) {
200 Status
= EFI_OUT_OF_RESOURCES
;
204 // Setup the device instance
206 MouseAbsolutePointerDev
->Signature
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE
;
207 MouseAbsolutePointerDev
->Handle
= Controller
;
208 MouseAbsolutePointerDev
->SampleRate
= SampleRate20
;
209 MouseAbsolutePointerDev
->Resolution
= MouseResolution4
;
210 MouseAbsolutePointerDev
->Scaling
= Scaling1
;
211 MouseAbsolutePointerDev
->DataPackageSize
= 3;
212 MouseAbsolutePointerDev
->IsaIo
= IsaIo
;
213 MouseAbsolutePointerDev
->DevicePath
= ParentDevicePath
;
216 // Resolution = 4 counts/mm
218 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxX
= 1024;
219 MouseAbsolutePointerDev
->Mode
.AbsoluteMinX
= 0;
220 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxY
= 798;
221 MouseAbsolutePointerDev
->Mode
.AbsoluteMinY
= 0;
222 MouseAbsolutePointerDev
->Mode
.AbsoluteMaxZ
= 0;
223 MouseAbsolutePointerDev
->Mode
.AbsoluteMinZ
= 0;
224 MouseAbsolutePointerDev
->Mode
.Attributes
= 0x03;
226 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Reset
= MouseAbsolutePointerReset
;
227 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.GetState
= MouseAbsolutePointerGetState
;
228 MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Mode
= &(MouseAbsolutePointerDev
->Mode
);
231 // Initialize keyboard controller if necessary
233 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
235 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
239 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
240 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
241 Status
= KbcSelfTest (IsaIo
);
242 if (EFI_ERROR (Status
)) {
243 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
248 KbcEnableAux (IsaIo
);
250 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
252 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
259 Status
= MouseAbsolutePointerDev
->AbsolutePointerProtocol
.Reset (
260 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
,
261 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
263 if (EFI_ERROR (Status
)) {
265 // mouse not connected
267 Status
= EFI_SUCCESS
;
268 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
272 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
274 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
279 // Setup the WaitForKey event
281 Status
= gBS
->CreateEvent (
284 MouseAbsolutePointerWaitForInput
,
285 MouseAbsolutePointerDev
,
286 &((MouseAbsolutePointerDev
->AbsolutePointerProtocol
).WaitForInput
)
288 if (EFI_ERROR (Status
)) {
289 Status
= EFI_OUT_OF_RESOURCES
;
293 // Setup a periodic timer, used to poll mouse state
295 Status
= gBS
->CreateEvent (
296 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
298 PollMouseAbsolutePointer
,
299 MouseAbsolutePointerDev
,
300 &MouseAbsolutePointerDev
->TimerEvent
302 if (EFI_ERROR (Status
)) {
303 Status
= EFI_OUT_OF_RESOURCES
;
307 // Start timer to poll mouse (100 samples per second)
309 Status
= gBS
->SetTimer (MouseAbsolutePointerDev
->TimerEvent
, TimerPeriodic
, 100000);
310 if (EFI_ERROR (Status
)) {
311 Status
= EFI_OUT_OF_RESOURCES
;
315 MouseAbsolutePointerDev
->ControllerNameTable
= NULL
;
318 gPs2MouseAbsolutePointerComponentName
.SupportedLanguages
,
319 &MouseAbsolutePointerDev
->ControllerNameTable
,
320 L
"Faked PS/2 Touchpad Device",
325 gPs2MouseAbsolutePointerComponentName2
.SupportedLanguages
,
326 &MouseAbsolutePointerDev
->ControllerNameTable
,
327 L
"Faked PS/2 Touchpad Device",
333 // Install protocol interfaces for the mouse device.
335 Status
= gBS
->InstallMultipleProtocolInterfaces (
337 &gEfiAbsolutePointerProtocolGuid
,
338 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
,
341 if (EFI_ERROR (Status
)) {
345 gBS
->RestoreTPL (OldTpl
);
351 KbcDisableAux (IsaIo
);
353 if (StatusCode
!= 0) {
354 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
355 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
361 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
!= NULL
)) {
362 gBS
->CloseEvent (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
);
365 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->TimerEvent
!= NULL
)) {
366 gBS
->CloseEvent (MouseAbsolutePointerDev
->TimerEvent
);
369 if ((MouseAbsolutePointerDev
!= NULL
) && (MouseAbsolutePointerDev
->ControllerNameTable
!= NULL
)) {
370 FreeUnicodeStringTable (MouseAbsolutePointerDev
->ControllerNameTable
);
373 // Since there will be no timer handler for mouse input any more,
374 // exhaust input data just in case there is still mouse data left
376 EmptyStatus
= EFI_SUCCESS
;
377 while (!EFI_ERROR (EmptyStatus
)) {
378 EmptyStatus
= In8042Data (IsaIo
, &Data
);
381 if (MouseAbsolutePointerDev
!= NULL
) {
382 FreePool (MouseAbsolutePointerDev
);
387 &gEfiDevicePathProtocolGuid
,
388 This
->DriverBindingHandle
,
394 &gEfiIsaIoProtocolGuid
,
395 This
->DriverBindingHandle
,
399 gBS
->RestoreTPL (OldTpl
);
405 Stop this driver on ControllerHandle. Support stopping any child handles
406 created by this driver.
408 @param This Protocol instance pointer.
409 @param ControllerHandle Handle of device to stop driver on
410 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
411 children is zero stop the entire bus driver.
412 @param ChildHandleBuffer List of Child Handles to Stop.
414 @retval EFI_SUCCESS This driver is removed ControllerHandle
415 @retval other This driver was not removed from this device
420 PS2MouseAbsolutePointerDriverStop (
421 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
422 IN EFI_HANDLE Controller
,
423 IN UINTN NumberOfChildren
,
424 IN EFI_HANDLE
*ChildHandleBuffer
428 EFI_ABSOLUTE_POINTER_PROTOCOL
*AbsolutePointerProtocol
;
429 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
432 Status
= gBS
->OpenProtocol (
434 &gEfiAbsolutePointerProtocolGuid
,
435 (VOID
**) &AbsolutePointerProtocol
,
436 This
->DriverBindingHandle
,
438 EFI_OPEN_PROTOCOL_GET_PROTOCOL
440 if (EFI_ERROR (Status
)) {
444 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (AbsolutePointerProtocol
);
447 // Report that the keyboard is being disabled
449 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
451 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
452 MouseAbsolutePointerDev
->DevicePath
455 Status
= gBS
->UninstallProtocolInterface (
457 &gEfiAbsolutePointerProtocolGuid
,
458 &MouseAbsolutePointerDev
->AbsolutePointerProtocol
460 if (EFI_ERROR (Status
)) {
465 // Cancel mouse data polling timer, close timer event
467 gBS
->SetTimer (MouseAbsolutePointerDev
->TimerEvent
, TimerCancel
, 0);
468 gBS
->CloseEvent (MouseAbsolutePointerDev
->TimerEvent
);
471 // Since there will be no timer handler for mouse input any more,
472 // exhaust input data just in case there is still mouse data left
474 Status
= EFI_SUCCESS
;
475 while (!EFI_ERROR (Status
)) {
476 Status
= In8042Data (MouseAbsolutePointerDev
->IsaIo
, &Data
);
479 gBS
->CloseEvent (MouseAbsolutePointerDev
->AbsolutePointerProtocol
.WaitForInput
);
480 FreeUnicodeStringTable (MouseAbsolutePointerDev
->ControllerNameTable
);
481 FreePool (MouseAbsolutePointerDev
);
485 &gEfiDevicePathProtocolGuid
,
486 This
->DriverBindingHandle
,
492 &gEfiIsaIoProtocolGuid
,
493 This
->DriverBindingHandle
,
501 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and there is a mouse device connected to system.
503 @param This - Pointer of simple pointer Protocol.
504 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
507 @retval EFI_SUCCESS - The command byte is written successfully.
508 @retval EFI_DEVICE_ERROR - Errors occurred during resetting keyboard.
513 MouseAbsolutePointerReset (
514 IN EFI_ABSOLUTE_POINTER_PROTOCOL
*This
,
515 IN BOOLEAN ExtendedVerification
519 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
521 BOOLEAN KeyboardEnable
;
524 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This
);
527 // Report reset progress code
529 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
531 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
532 MouseAbsolutePointerDev
->DevicePath
535 KeyboardEnable
= FALSE
;
538 // Raise TPL to avoid keyboard operation impact
540 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
542 ZeroMem (&MouseAbsolutePointerDev
->State
, sizeof (EFI_ABSOLUTE_POINTER_STATE
));
543 MouseAbsolutePointerDev
->StateChanged
= FALSE
;
546 // Exhaust input data
548 Status
= EFI_SUCCESS
;
549 while (!EFI_ERROR (Status
)) {
550 Status
= In8042Data (MouseAbsolutePointerDev
->IsaIo
, &Data
);
553 CheckKbStatus (MouseAbsolutePointerDev
->IsaIo
, &KeyboardEnable
);
555 KbcDisableKb (MouseAbsolutePointerDev
->IsaIo
);
557 MouseAbsolutePointerDev
->IsaIo
->Io
.Read (MouseAbsolutePointerDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
560 // if there's data block on KBC data port, read it out
562 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
563 MouseAbsolutePointerDev
->IsaIo
->Io
.Read (MouseAbsolutePointerDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
566 Status
= EFI_SUCCESS
;
568 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
569 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
570 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
572 if (ExtendedVerification
&& CheckMouseAbsolutePointerConnect (MouseAbsolutePointerDev
)) {
574 // Send mouse reset command and set mouse default configure
576 Status
= PS2MouseReset (MouseAbsolutePointerDev
->IsaIo
);
577 if (EFI_ERROR (Status
)) {
578 Status
= EFI_DEVICE_ERROR
;
582 Status
= PS2MouseSetSampleRate (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->SampleRate
);
583 if (EFI_ERROR (Status
)) {
584 Status
= EFI_DEVICE_ERROR
;
588 Status
= PS2MouseSetResolution (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->Resolution
);
589 if (EFI_ERROR (Status
)) {
590 Status
= EFI_DEVICE_ERROR
;
594 Status
= PS2MouseSetScaling (MouseAbsolutePointerDev
->IsaIo
, MouseAbsolutePointerDev
->Scaling
);
595 if (EFI_ERROR (Status
)) {
596 Status
= EFI_DEVICE_ERROR
;
600 Status
= PS2MouseEnable (MouseAbsolutePointerDev
->IsaIo
);
601 if (EFI_ERROR (Status
)) {
602 Status
= EFI_DEVICE_ERROR
;
607 gBS
->RestoreTPL (OldTpl
);
609 if (KeyboardEnable
) {
610 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
617 Check whether there is Ps/2 mouse device in system
619 @param MouseAbsolutePointerDev - Absolute Pointer Device Private Data Structure
621 @retval TRUE - Keyboard in System.
622 @retval FALSE - Keyboard not in System.
626 CheckMouseAbsolutePointerConnect (
627 IN PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
633 Status
= PS2MouseEnable (MouseAbsolutePointerDev
->IsaIo
);
634 if (!EFI_ERROR (Status
)) {
642 Get and Clear mouse status.
644 @param This - Pointer of simple pointer Protocol.
645 @param State - Output buffer holding status.
647 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
648 @retval EFI_NOT_READY Mouse is not changed status yet.
649 @retval EFI_SUCCESS Mouse status is changed and get successful.
653 MouseAbsolutePointerGetState (
654 IN EFI_ABSOLUTE_POINTER_PROTOCOL
*This
,
655 IN OUT EFI_ABSOLUTE_POINTER_STATE
*State
658 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
661 MouseAbsolutePointerDev
= PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This
);
664 return EFI_INVALID_PARAMETER
;
667 if (!MouseAbsolutePointerDev
->StateChanged
) {
668 return EFI_NOT_READY
;
671 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
672 CopyMem (State
, &(MouseAbsolutePointerDev
->State
), sizeof (EFI_ABSOLUTE_POINTER_STATE
));
677 MouseAbsolutePointerDev
->State
.CurrentX
= 0;
678 MouseAbsolutePointerDev
->State
.CurrentY
= 0;
679 MouseAbsolutePointerDev
->State
.CurrentZ
= 0;
680 MouseAbsolutePointerDev
->State
.ActiveButtons
= 0x0;
681 MouseAbsolutePointerDev
->StateChanged
= FALSE
;
682 gBS
->RestoreTPL (OldTpl
);
689 Event notification function for SIMPLE_POINTER.WaitForInput event.
690 Signal the event if there is input from mouse.
692 @param Event event object
693 @param Context event context
698 MouseAbsolutePointerWaitForInput (
703 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
705 MouseAbsolutePointerDev
= (PS2_MOUSE_ABSOLUTE_POINTER_DEV
*) Context
;
708 // Someone is waiting on the mouse event, if there's
709 // input from mouse, signal the event
711 if (MouseAbsolutePointerDev
->StateChanged
) {
712 gBS
->SignalEvent (Event
);
718 Event notification function for TimerEvent event.
719 If mouse device is connected to system, try to get the mouse packet data.
721 @param Event - TimerEvent in PS2_MOUSE_DEV
722 @param Context - Pointer to PS2_MOUSE_DEV structure
727 PollMouseAbsolutePointer(
733 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
;
735 MouseAbsolutePointerDev
= (PS2_MOUSE_ABSOLUTE_POINTER_DEV
*) Context
;
738 // Polling mouse packet data
740 PS2MouseGetPacket (MouseAbsolutePointerDev
);
744 The user Entry Point for module Ps2MouseAbsolutePointer. The user code starts with this function.
746 @param[in] ImageHandle The firmware allocated handle for the EFI image.
747 @param[in] SystemTable A pointer to the EFI System Table.
749 @retval EFI_SUCCESS The entry point is executed successfully.
750 @retval other Some error occurs when executing this entry point.
755 InitializePs2MouseAbsolutePointer(
756 IN EFI_HANDLE ImageHandle
,
757 IN EFI_SYSTEM_TABLE
*SystemTable
763 // Install driver model protocol(s).
765 Status
= EfiLibInstallDriverBindingComponentName2 (
768 &gPS2MouseAbsolutePointerDriver
,
770 &gPs2MouseAbsolutePointerComponentName
,
771 &gPs2MouseAbsolutePointerComponentName2
773 ASSERT_EFI_ERROR (Status
);